diff options
author | Ilya Etingof <etingof@gmail.com> | 2017-10-11 22:09:34 +0200 |
---|---|---|
committer | Ilya Etingof <etingof@gmail.com> | 2017-10-11 22:09:34 +0200 |
commit | a4bf67e7178c97375ecfc85ff57def3b4a96b981 (patch) | |
tree | e0c2c09fe0bd016e707980c4feff1e93f4a32134 | |
parent | d83c99d986376e1a7d7a200132dd6fc6d12bdcd5 (diff) | |
parent | a7d88710444459a9b634a9a0735221b80ceb68c3 (diff) | |
download | pyasn1-git-a4bf67e7178c97375ecfc85ff57def3b4a96b981.tar.gz |
Merge branch 'devel-0.4.1' of github.com:etingof/pyasn1 into devel-0.4.1
-rw-r--r-- | CHANGES.rst | 1 | ||||
-rw-r--r-- | MANIFEST.in | 2 | ||||
-rw-r--r-- | doc/source/.templates/layout.html | 189 | ||||
-rw-r--r-- | doc/source/docs/api-reference.rst | 31 | ||||
-rw-r--r-- | doc/source/docs/tutorial.rst | 1778 | ||||
-rw-r--r-- | doc/source/docs/type/char/contents.rst | 20 | ||||
-rw-r--r-- | doc/source/docs/type/namedtype/contents.rst | 11 | ||||
-rw-r--r-- | doc/source/docs/type/tag/contents.rst | 10 | ||||
-rw-r--r-- | doc/source/docs/type/univ/contents.rst | 23 | ||||
-rw-r--r-- | doc/source/docs/type/useful/contents.rst | 10 | ||||
-rw-r--r-- | docs/Makefile (renamed from doc/Makefile) | 0 | ||||
-rw-r--r-- | docs/source/.static/css/rtdimproved.css (renamed from doc/source/.static/css/rtdimproved.css) | 0 | ||||
-rw-r--r-- | docs/source/changelog.rst (renamed from doc/source/changelog.rst) | 0 | ||||
-rw-r--r-- | docs/source/conf.py (renamed from doc/source/conf.py) | 7 | ||||
-rw-r--r-- | docs/source/contents.rst (renamed from doc/source/contents.rst) | 16 | ||||
-rw-r--r-- | docs/source/example-use-case.rst (renamed from doc/source/example-use-case.rst) | 0 | ||||
-rw-r--r-- | docs/source/license.rst (renamed from doc/source/license.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/codec/ber/contents.rst (renamed from doc/source/docs/codec/ber/contents.rst) | 2 | ||||
-rw-r--r-- | docs/source/pyasn1/codec/cer/contents.rst (renamed from doc/source/docs/codec/cer/contents.rst) | 2 | ||||
-rw-r--r-- | docs/source/pyasn1/codec/der/contents.rst (renamed from doc/source/docs/codec/der/contents.rst) | 2 | ||||
-rw-r--r-- | docs/source/pyasn1/codec/native/contents.rst (renamed from doc/source/docs/codec/native/contents.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/contents.rst | 26 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/bmpstring.rst (renamed from doc/source/docs/type/char/bmpstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/contents.rst | 20 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/generalstring.rst (renamed from doc/source/docs/type/char/generalstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/graphicstring.rst (renamed from doc/source/docs/type/char/graphicstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/ia5string.rst (renamed from doc/source/docs/type/char/ia5string.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/iso646string.rst (renamed from doc/source/docs/type/char/iso646string.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/numericstring.rst (renamed from doc/source/docs/type/char/numericstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/printablestring.rst (renamed from doc/source/docs/type/char/printablestring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/t61string.rst (renamed from doc/source/docs/type/char/t61string.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/teletexstring.rst (renamed from doc/source/docs/type/char/teletexstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/universalstring.rst (renamed from doc/source/docs/type/char/universalstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/utf8string.rst (renamed from doc/source/docs/type/char/utf8string.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/videotexstring.rst (renamed from doc/source/docs/type/char/videotexstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/char/visiblestring.rst (renamed from doc/source/docs/type/char/visiblestring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedtype/contents.rst | 11 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedtype/defaultednamedtype.rst (renamed from doc/source/docs/type/namedtype/defaultednamedtype.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedtype/namedtype.rst (renamed from doc/source/docs/type/namedtype/namedtype.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedtype/namedtypes.rst (renamed from doc/source/docs/type/namedtype/namedtypes.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedtype/optionalnamedtype.rst (renamed from doc/source/docs/type/namedtype/optionalnamedtype.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedval/contents.rst (renamed from doc/source/docs/type/namedval/contents.rst) | 2 | ||||
-rw-r--r-- | docs/source/pyasn1/type/namedval/namedval.rst (renamed from doc/source/docs/type/namedval/namedval.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/opentype/contents.rst (renamed from doc/source/docs/type/opentype/contents.rst) | 2 | ||||
-rw-r--r-- | docs/source/pyasn1/type/opentype/opentype.rst (renamed from doc/source/docs/type/opentype/opentype.rst) | 3 | ||||
-rw-r--r-- | docs/source/pyasn1/type/tag/contents.rst | 10 | ||||
-rw-r--r-- | docs/source/pyasn1/type/tag/tag.rst (renamed from doc/source/docs/type/tag/tag.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/tag/tagmap.rst (renamed from doc/source/docs/type/tag/tagmap.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/tag/tagset.rst (renamed from doc/source/docs/type/tag/tagset.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/any.rst (renamed from doc/source/docs/type/univ/any.rst) | 8 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/bitstring.rst (renamed from doc/source/docs/type/univ/bitstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/boolean.rst (renamed from doc/source/docs/type/univ/boolean.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/choice.rst (renamed from doc/source/docs/type/univ/choice.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/contents.rst | 23 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/enumerated.rst (renamed from doc/source/docs/type/univ/enumerated.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/integer.rst (renamed from doc/source/docs/type/univ/integer.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/null.rst (renamed from doc/source/docs/type/univ/null.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/objectidentifier.rst (renamed from doc/source/docs/type/univ/objectidentifier.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/octetstring.rst (renamed from doc/source/docs/type/univ/octetstring.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/real.rst (renamed from doc/source/docs/type/univ/real.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/sequence.rst (renamed from doc/source/docs/type/univ/sequence.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/sequenceof.rst (renamed from doc/source/docs/type/univ/sequenceof.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/set.rst (renamed from doc/source/docs/type/univ/set.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/univ/setof.rst (renamed from doc/source/docs/type/univ/setof.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/useful/contents.rst | 10 | ||||
-rw-r--r-- | docs/source/pyasn1/type/useful/generalizedtime.rst (renamed from doc/source/docs/type/useful/generalizedtime.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/useful/objectdescriptor.rst (renamed from doc/source/docs/type/useful/objectdescriptor.rst) | 0 | ||||
-rw-r--r-- | docs/source/pyasn1/type/useful/utctime.rst (renamed from doc/source/docs/type/useful/utctime.rst) | 0 | ||||
-rw-r--r-- | pyasn1/codec/cer/encoder.py | 6 | ||||
-rw-r--r-- | pyasn1/codec/der/encoder.py | 6 | ||||
-rw-r--r-- | pyasn1/type/base.py | 60 | ||||
-rw-r--r-- | pyasn1/type/char.py | 6 | ||||
-rw-r--r-- | pyasn1/type/univ.py | 122 |
73 files changed, 226 insertions, 2193 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 0c1cb55..20adcde 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ Revision 0.4.1, released XX-10-2017 or a Python value plus ASN.1 schema - BitString decoder optimised for better performance when running on constructed encoding +- Sphinx documentation reaaranged, simplified and reworded Revision 0.3.7, released 04-10-2017 ----------------------------------- diff --git a/MANIFEST.in b/MANIFEST.in index 28d20e7..b01e357 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ include *.rst *.md recursive-include tests *.py -recursive-include doc Makefile *.rst conf.py +recursive-include docs Makefile *.rst conf.py prune doc/build prune doc/source/.templates
\ No newline at end of file diff --git a/doc/source/.templates/layout.html b/doc/source/.templates/layout.html deleted file mode 100644 index 9cb875a..0000000 --- a/doc/source/.templates/layout.html +++ /dev/null @@ -1,189 +0,0 @@ -{# TEMPLATE VAR SETTINGS #} -{%- set url_root = pathto('', 1) %} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} -{%- if not embedded and docstitle %} - {%- set titlesuffix = " — "|safe + docstitle|e %} -{%- else %} - {%- set titlesuffix = "" %} -{%- endif %} - -<!DOCTYPE html> -<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> -<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> -<head> - <meta charset="utf-8"> - {{ metatags }} - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - {% block htmltitle %} - <title>{{ title|striptags|e }}{{ titlesuffix }}</title> - {% endblock %} - - {# FAVICON #} - {% if favicon %} - <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/> - {% endif %} - - {# CSS #} - - {# OPENSEARCH #} - {% if not embedded %} - {% if use_opensearch %} - <link rel="search" type="application/opensearchdescription+xml" title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}" href="{{ pathto('_static/opensearch.xml', 1) }}"/> - {% endif %} - - {% endif %} - - {# RTD hosts this file, so just load on non RTD builds #} - {% if not READTHEDOCS %} - <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" /> - {% endif %} - - {% for cssfile in css_files %} - <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" /> - {% endfor %} - - {% for cssfile in extra_css_files %} - <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" /> - {% endfor %} - - {%- block linktags %} - {%- if hasdoc('about') %} - <link rel="author" title="{{ _('About these documents') }}" - href="{{ pathto('about') }}"/> - {%- endif %} - {%- if hasdoc('genindex') %} - <link rel="index" title="{{ _('Index') }}" - href="{{ pathto('genindex') }}"/> - {%- endif %} - {%- if hasdoc('search') %} - <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}"/> - {%- endif %} - {%- if hasdoc('copyright') %} - <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}"/> - {%- endif %} - <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}"/> - {%- if parents %} - <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}"/> - {%- endif %} - {%- if next %} - <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}"/> - {%- endif %} - {%- if prev %} - <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}"/> - {%- endif %} - {%- endblock %} - {%- block extrahead %} {% endblock %} - - {# Keep modernizr in head - http://modernizr.com/docs/#installing #} - <script src="_static/js/modernizr.min.js"></script> - -</head> - -<body class="wy-body-for-nav" role="document"> - - <div class="wy-grid-for-nav"> - - {# SIDE NAV, TOGGLES ON MOBILE #} - <nav data-toggle="wy-nav-shift" class="wy-nav-side"> - <div class="wy-side-nav-search"> - {% block sidebartitle %} - - {% if logo and theme_logo_only %} - <a href="{{ pathto(master_doc) }}"> - {% else %} - <a href="{{ pathto(master_doc) }}" class="icon icon-home"> {{ project }} - {% endif %} - - {% if logo %} - {# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #} - <img src="{{ pathto('_static/' + logo, 1) }}" class="logo" /> - {% endif %} - </a> - - {% include "searchbox.html" %} - - {% endblock %} - </div> - - <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation"> - {% block menu %} - {% set toctree = toctree(maxdepth=4, collapse=True, includehidden=True) %} - {% if toctree %} - {{ toctree }} - {% else %} - <!-- Local TOC --> - <div class="local-toc">{{ toc }}</div> - {% endif %} - {% endblock %} - </div> - - </nav> - - <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"> - - {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #} - <nav class="wy-nav-top" role="navigation" aria-label="top navigation"> - <i data-toggle="wy-nav-top" class="fa fa-bars"></i> - <a href="{{ pathto(master_doc) }}">{{ project }}</a> - </nav> - - - {# PAGE CONTENT #} - <div class="wy-nav-content"> - <div class="rst-content"> - {% include "breadcrumbs.html" %} - <div role="main" class="document"> - {% if include_analytics %} - {% include "top.html" %} - {% endif %} - {% block body %}{% endblock %} - {% if include_analytics %} - {% include "bottom.html" %} - {% include "analytics.html" %} - {% endif %} - <hr/> - </div> - {% include "footer.html" %} - </div> - </div> - - </section> - - </div> - {% include "versions.html" %} - - {% if not embedded %} - - <script type="text/javascript"> - var DOCUMENTATION_OPTIONS = { - URL_ROOT:'{{ url_root }}', - VERSION:'{{ release|e }}', - COLLAPSE_INDEX:false, - FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}', - HAS_SOURCE: {{ has_source|lower }} - }; - </script> - {%- for scriptfile in script_files %} - <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script> - {%- endfor %} - - {% endif %} - - {# RTD hosts this file, so just load on non RTD builds #} - {% if not READTHEDOCS %} - <script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script> - {% endif %} - - {# STICKY NAVIGATION #} - {% if theme_sticky_navigation %} - <script type="text/javascript"> - jQuery(function () { - SphinxRtdTheme.StickyNav.enable(); - }); - </script> - {% endif %} - - {%- block footer %} {% endblock %} - -</body> -</html> diff --git a/doc/source/docs/api-reference.rst b/doc/source/docs/api-reference.rst deleted file mode 100644 index d80c45a..0000000 --- a/doc/source/docs/api-reference.rst +++ /dev/null @@ -1,31 +0,0 @@ - -Library reference -================= - -.. toctree:: - :maxdepth: 2 - -ASN.1 types ------------ - -.. toctree:: - :maxdepth: 2 - - /docs/type/univ/contents - /docs/type/char/contents - /docs/type/useful/contents - /docs/type/tag/contents - /docs/type/namedtype/contents - /docs/type/opentype/contents - /docs/type/namedval/contents - -Transformation codecs ---------------------- - -.. toctree:: - :maxdepth: 2 - - /docs/codec/ber/contents - /docs/codec/cer/contents - /docs/codec/der/contents - /docs/codec/native/contents diff --git a/doc/source/docs/tutorial.rst b/doc/source/docs/tutorial.rst deleted file mode 100644 index c072a6b..0000000 --- a/doc/source/docs/tutorial.rst +++ /dev/null @@ -1,1778 +0,0 @@ - -Documentation -============= - -.. toctree:: - :maxdepth: 2 - -Data model for ASN.1 types --------------------------- - -All ASN.1 types could be categorized into two groups: scalar (also -called simple or primitive) and constructed. The first group is -populated by well-known types like Integer or String. Members of -constructed group hold other types (simple or constructed) as their -inner components, thus they are semantically close to a programming -language records or lists. - -In pyasn1, all ASN.1 types and values are implemented as Python -objects. The same pyasn1 object can represent either ASN.1 type -and/or value depending of the presense of value initializer on object -instantiation. We will further refer to these as *pyasn1 type object* -versus *pyasn1 value object*. - -Primitive ASN.1 types are implemented as immutable scalar objects. -There values could be used just like corresponding native Python -values (integers, strings/bytes etc) and freely mixed with them in -expressions. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> asn1IntegerValue = univ.Integer(12) - >>> asn1IntegerValue - 2 - 10 - >>> univ.OctetString('abc') == 'abc' - True # Python 2 - >>> univ.OctetString(b'abc') == b'abc' - True # Python 3 - -It would be an error to perform an operation on a pyasn1 type object -as it holds no value to deal with: - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> asn1IntegerType = univ.Integer() - >>> asn1IntegerType - 2 - ... - pyasn1.error.PyAsn1Error: No value for __coerce__() - - -Scalar types ------------- - -In the sub-sections that follow we will explain pyasn1 mapping to -those primitive ASN.1 types. Both, ASN.1 notation and corresponding -pyasn1 syntax will be given in each case. - -Boolean type -++++++++++++ - -*BOOLEAN* is the simplest type those values could be either True or -False. - -.. code-block:: bash - - ;; type specification - FunFactorPresent ::= BOOLEAN - - ;; values declaration and assignment - pythonFunFactor FunFactorPresent ::= TRUE - cobolFunFactor FunFactorPresent :: FALSE - -And here's pyasn1 version of :py:class:`~pyasn1.type.univ.Boolean`: - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> class FunFactorPresent(univ.Boolean): pass - ... - >>> pythonFunFactor = FunFactorPresent(True) - >>> cobolFunFactor = FunFactorPresent(False) - >>> pythonFunFactor - FunFactorPresent('True(1)') - >>> cobolFunFactor - FunFactorPresent('False(0)') - >>> pythonFunFactor == cobolFunFactor - False - >>> - -Null type -+++++++++ - -The *NULL* type is sometimes used to express the absense of -information. - -.. code-block:: bash - - ;; type specification - Vote ::= CHOICE { - agreed BOOLEAN, - skip NULL - } - - ;; value declaration and assignment - myVote Vote ::= skip:NULL - -We will explain the CHOICE type later on, meanwhile the -:py:class:`~pyasn1.type.univ.Null` type: - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> skip = univ.Null() - >>> skip - Null('') - >>> - -Integer type -++++++++++++ - -ASN.1 defines the values of *INTEGER* type as negative or positive of -whatever length. This definition plays nicely with Python as the -latter places no limit on Integers. However, some ASN.1 -implementations may impose certain limits of integer value ranges. -Keep that in mind when designing new data structures. - -.. code-block:: bash - - ;; values specification - age-of-universe INTEGER ::= 13750000000 - mean-martian-surface-temperature INTEGER ::= -63 - -A rather strigntforward mapping into pyasn1 - -:py:class:`~pyasn1.type.univ.Integer`: - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> ageOfUniverse = univ.Integer(13750000000) - >>> ageOfUniverse - Integer(13750000000) - >>> - >>> meanMartianSurfaceTemperature = univ.Integer(-63) - >>> meanMartianSurfaceTemperature - Integer(-63) - >>> - -ASN.1 allows to assign human-friendly names to particular values of -an INTEGER type. - -.. code-block:: bash - - Temperature ::= INTEGER { - freezing(0), - boiling(100) - } - -The Temperature type expressed in pyasn1: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedval - >>> class Temperature(univ.Integer): - ... namedValues = namedval.NamedValues(('freezing', 0), ('boiling', 100)) - ... - >>> t = Temperature(0) - >>> t - Temperature('freezing(0)') - >>> t + 1 - Temperature(1) - >>> t + 100 - Temperature('boiling(100)') - >>> t = Temperature('boiling') - >>> t - Temperature('boiling(100)') - >>> Temperature('boiling') / 2 - Temperature(50) - >>> -1 < Temperature('freezing') - True - >>> 47 > Temperature('boiling') - False - -These values labels have no effect on Integer type operations, any value -still could be assigned to a type (information on value constraints will -follow further in the documentation). - -Enumerated type -+++++++++++++++ - -ASN.1 *ENUMERATED* type differs from an Integer type in a number of -ways. Most important is that its instance can only hold a value that -belongs to a set of values specified on type declaration. - -.. code-block:: bash - - error-status ::= ENUMERATED { - no-error(0), - authentication-error(10), - authorization-error(20), - general-failure(51) - } - -When constructing :py:class:`~pyasn1.type.univ.Enumerated` type we -will use two pyasn1 features: values labels (as mentioned above) and -value constraint (will be described in more details later on). - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedval, constraint - >>> class ErrorStatus(univ.Enumerated): - ... namedValues = namedval.NamedValues( - ... ('no-error', 0), - ... ('authentication-error', 10), - ... ('authorization-error', 20), - ... ('general-failure', 51) - ... ) - ... subtypeSpec = univ.Enumerated.subtypeSpec + \ - ... constraint.SingleValueConstraint(0, 10, 20, 51) - ... - >>> errorStatus = univ.ErrorStatus('no-error') - >>> errorStatus - ErrorStatus('no-error(0)') - >>> errorStatus == univ.ErrorStatus('general-failure') - False - >>> univ.ErrorStatus('non-existing-state') - Traceback (most recent call last): - ... - pyasn1.error.PyAsn1Error: Can't coerce non-existing-state into integer - >>> - -Particular integer values associated with Enumerated value states have -no meaning. They should not be used as such or in any kind of math -operation. Those integer values are only used by codecs to transfer -state from one entity to another. - -Real type -+++++++++ - -Values of the *REAL* type are a three-component tuple of mantissa, -base and exponent. All three are integers. - -.. code-block:: bash - - pi ::= REAL { mantissa 314159, base 10, exponent -5 } - -Corresponding pyasn1 :py:class:`~pyasn1.type.univ.Real` objects can be -initialized with either a three-component tuple or a Python float. -Infinite values could be expressed in a way, compatible with Python -float type. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> pi = univ.Real((314159, 10, -5)) - >>> pi - Real((314159, 10,-5)) - >>> float(pi) - 3.14159 - >>> pi == univ.Real(3.14159) - True - >>> univ.Real('inf') - Real('inf') - >>> univ.Real('-inf') == float('-inf') - True - >>> - -If a Real object is initialized from a Python float or yielded by a math -operation, the base is set to decimal 10 (what affects encoding). - -Bit string type -+++++++++++++++ - -ASN.1 *BIT STRING* type holds opaque binary data of an arbitrarily -length. A BIT STRING value could be initialized by either a binary -(base 2) or hex (base 16) value. - -.. code-block:: bash - - public-key BIT STRING ::= '1010111011110001010110101101101 - 1011000101010000010110101100010 - 0110101010000111101010111111110'B - - signature BIT STRING ::= 'AF01330CD932093392100B39FF00DE0'H - -The pyasn1 :py:class:`~pyasn1.type.univ.BitString` objects can -initialize from native ASN.1 notation (base 2 or base 16 strings) or -from a Python tuple of binary components. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> publicKey = univ.BitString( - ... binValue='1010111011110001010110101101101' - ... '1011000101010000010110101100010' - ... '0110101010000111101010111111110' - ) - >>> publicKey - BitString(binValue='101011101111000101011010110110110110001010100000101101011000100110101010000111101010111111110') - >>> signature = univ.BitString( - ... hexValue='AF01330CD932093392100B39FF00DE0' - ... ) - >>> signature - BitString(binValue='1010111100000001001100110000110011011001001100100000100100110011100100100001000000001011001110011111111100000000110111100000') - >>> fingerprint = univ.BitString( - ... (1, 0, 1, 1 ,0, 1, 1, 1, 0, 1, 0, 1) - ... ) - >>> fingerprint - BitString(binValue='101101110101') - >>> - -Another BIT STRING initialization method supported by ASN.1 notation -is to specify only 1-th bits along with their human-friendly label and -bit offset relative to the beginning of the bit string. With this -method, all not explicitly mentioned bits are doomed to be zeros. - -.. code-block:: bash - - bit-mask BIT STRING ::= { - read-flag(0), - write-flag(2), - run-flag(4) - } - -To express this in pyasn1, we will employ the named values feature (as -with Enumeration type). - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedval - >>> class BitMask(univ.BitString): - ... namedValues = namedval.NamedValues( - ... ('read-flag', 0), - ... ('write-flag', 2), - ... ('run-flag', 4) - ... ) - >>> bitMask = BitMask('read-flag,run-flag') - >>> bitMask - BitMask(binValue='10001') - >>> tuple(bitMask) - (1, 0, 0, 0, 1) - >>> bitMask[4] - 1 - >>> - -The BitString objects mimic the properties of Python tuple type in -part of immutable sequence object protocol support. - -OctetString type -++++++++++++++++ - -The *OCTET STRING* type is a confusing subject. According to ASN.1 -specification, this type is similar to BIT STRING, the major -difference is that the former operates in 8-bit chunks of data. What -is important to note, is that OCTET STRING was NOT designed to handle -text strings - the standard provides many other types specialized for -text content. For that reason, ASN.1 forbids to initialize OCTET -STRING values with "quoted text strings", only binary or hex -initializers, similar to BIT STRING ones, are allowed. - -.. code-block:: bash - - thumbnail OCTET STRING ::= '1000010111101110101111000000111011'B - thumbnail OCTET STRING ::= 'FA9823C43E43510DE3422'H - -However, ASN.1 users (e.g. protocols designers) seem to ignore the -original purpose of the OCTET STRING type - they used it for handling -all kinds of data, including text strings. - -.. code-block:: bash - - welcome-message OCTET STRING ::= "Welcome to ASN.1 wilderness!" - -In pyasn1, we have taken a liberal approach and allowed both BIT -STRING style and quoted text initializers for the -:py:class:`~pyasn1.type.univ.OctetString` objects. To avoid possible -collisions, quoted text is the default initialization syntax. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> thumbnail = univ.OctetString( - ... binValue='1000010111101110101111000000111011' - ... ) - >>> thumbnail - OctetString(hexValue='85eebcec0') - >>> thumbnail = univ.OctetString( - ... hexValue='FA9823C43E43510DE3422' - ... ) - >>> thumbnail - OctetString(hexValue='fa9823c43e4351de34220') - >>> - -Most frequent usage of the OctetString class is to instantiate it with -a text string. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> welcomeMessage = univ.OctetString('Welcome to ASN.1 wilderness!') - >>> welcomeMessage - OctetString(b'Welcome to ASN.1 wilderness!') - >>> print('%s' % welcomeMessage) - Welcome to ASN.1 wilderness! - >>> welcomeMessage[11:16] - OctetString(b'ASN.1') - >>> - -OctetString objects support the immutable sequence object protocol. -In other words, they behave like Python 3 bytes (or Python 2 strings). -When running pyasn1 on Python 3, it's better to use the bytes objects for -OctetString instantiation, as it's more reliable and efficient. - -Additionally, OctetString's can also be instantiated with a sequence of -8-bit integers (ASCII codes). - -.. code-block:: pycon - - >>> univ.OctetString((77, 101, 101, 103, 111)) - OctetString(b'Meego') - -It is sometimes convenient to express OctetString instances as 8-bit -characters (Python 3 bytes or Python 2 strings) or 8-bit integers. - -.. code-block:: pycon - - >>> octetString = univ.OctetString('ABCDEF') - >>> octetString.asNumbers() - (65, 66, 67, 68, 69, 70) - >>> octetString.asOctets() - b'ABCDEF' - -ObjectIdentifier type -+++++++++++++++++++++ - -Values of the *OBJECT IDENTIFIER* type are sequences of integers that -could be used to identify virtually anything in the world. Various -ASN.1-based protocols employ OBJECT IDENTIFIERs for their own -identification needs. - -.. code-block:: bash - - internet-id OBJECT IDENTIFIER ::= { - iso(1) identified-organization(3) dod(6) internet(1) - } - -One of the natural ways to map OBJECT IDENTIFIER type into a Python -one is to use Python tuples of integers. So this approach is taken by -pyasn1's :py:class:`~pyasn1.type.univ.ObjectIdentifier` class. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> internetId = univ.ObjectIdentifier((1, 3, 6, 1)) - >>> internetId - ObjectIdentifier('1.3.6.1') - >>> internetId[2] - 6 - >>> internetId[1:3] - ObjectIdentifier('3.6') - -A more human-friendly "dotted" notation is also supported. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> univ.ObjectIdentifier('1.3.6.1') - ObjectIdentifier('1.3.6.1') - -Symbolic names of the arcs of object identifier, sometimes present in -ASN.1 specifications, are not preserved and used in pyasn1 objects. - -The ObjectIdentifier objects mimic the properties of Python tuple type in -part of immutable sequence object protocol support. - -Any type -++++++++ - -The ASN.1 ANY type is a kind of wildcard or placeholder that matches -any other type without knowing it in advance. ANY has no base tag. - -.. code-block:: bash - - Error ::= SEQUENCE { - code INTEGER, - parameter ANY DEFINED BY code - } - -The ANY type is frequently used in specifications, where exact type is -not yet agreed upon between communicating parties or the number of -possible alternatives of a type is infinite. Sometimes an auxiliary -selector is kept around to help parties indicate the kind of ANY -payload in effect ("code" in the example above). - -Values of the ANY type contain serialized ASN.1 value(s) in form of an -octet string. Therefore pyasn1 :py:class:`~pyasn1.type.univ.Any` value -object share the properties of pyasn1 OctetString object. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> someValue = univ.Any(b'\x02\x01\x01') - >>> someValue - Any(b'\x02\x01\x01') - >>> str(someValue) - '\x02\x01\x01' - >>> bytes(someValue) - b'\x02\x01\x01' - >>> - -Receiving application is supposed to explicitly deserialize the -content of Any value object, possibly using auxiliary selector for -figuring out its ASN.1 type to pick appropriate decoder. - -There will be some more talk and code snippets covering Any type in -the codecs chapters that follow. - -Character string types -++++++++++++++++++++++ - -ASN.1 standard introduces a diverse set of text-specific types. All of -them were designed to handle various types of characters. Some of -these types seem be obsolete nowdays, as their target technologies are -gone. Another issue to be aware of is that raw OCTET STRING type is -sometimes used in practice by ASN.1 users instead of specialized -character string types, despite explicit prohibition imposed by ASN.1 -specification. - -The two types are specific to ASN.1 are NumericString and PrintableString. - -.. code-block:: bash - - welcome-message ::= PrintableString { - "Welcome to ASN.1 text types" - } - - dial-pad-numbers ::= NumericString { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" - } - -Their pyasn1 implementations are -:py:class:`~pyasn1.type.char.PrintableString` and -:py:class:`~pyasn1.type.char.NumericString`: - -.. code-block:: pycon - - >>> from pyasn1.type import char - >>> '%s' % char.PrintableString("Welcome to ASN.1 text types") - 'Welcome to ASN.1 text types' - >>> dialPadNumbers = char.NumericString( - "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" - ) - >>> dialPadNumbers - NumericString(b'0123456789') - >>> - -The :py:class:`~pyasn1.type.char.VisibleString`, -:py:class:`~pyasn1.type.char.IA5String`, -:py:class:`~pyasn1.type.char.TeletexString`, -:py:class:`~pyasn1.type.char.VideotexString`, -:py:class:`~pyasn1.type.char.GraphicString` and -:py:class:`~pyasn1.type.char.GeneralString` types came to ASN.1 from -ISO standards on character sets. - -.. code-block:: pycon - - >>> from pyasn1.type import char - >>> char.VisibleString("abc") - VisibleString(b'abc') - >>> char.IA5String('abc') - IA5String(b'abc') - >>> char.TeletexString('abc') - TeletexString(b'abc') - >>> char.VideotexString('abc') - VideotexString(b'abc') - >>> char.GraphicString('abc') - GraphicString(b'abc') - >>> char.GeneralString('abc') - GeneralString(b'abc') - >>> - -The last three types are relatively recent addition to the family of -character string types: :py:class:`~pyasn1.type.char.UniversalString`, -:py:class:`~pyasn1.type.char.BMPString` and -:py:class:`~pyasn1.type.char.UTF8String`. - -.. code-block:: pycon - - >>> from pyasn1.type import char - >>> char.UniversalString("abc") - UniversalString(b'abc') - >>> char.BMPString('abc') - BMPString(b'abc') - >>> char.UTF8String('abc') - UTF8String(b'abc') - >>> utf8String = char.UTF8String('У попа была собака') - >>> utf8String - UTF8String(b'\xd0\xa3 \xd0\xbf\xd0\xbe\xd0\xbf\xd0\xb0 \xd0\xb1\xd1\x8b\xd0\xbb\xd0\xb0\xd1\x81\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xba\xd0\xb0') - >>> print(utf8String) - У попа была собака - >>> - -In pyasn1, all character type objects behave like Python strings. None -of them is currently constrained in terms of valid alphabet so it's up -to the data source to keep an eye on data validation for these types. - -Useful types -++++++++++++ - -There are three so-called useful types defined in the standard: -:py:class:`~pyasn1.type.useful.ObjectDescriptor`, -:py:class:`~pyasn1.type.useful.GeneralizedTime` and -:py:class:`~pyasn1.type.useful.UTCTime`. They all are subtypes of -GraphicString or VisibleString types therefore useful types are -character string types. - -It's advised by the ASN.1 standard to have an instance of -ObjectDescriptor type holding a human-readable description of -corresponding instance of OBJECT IDENTIFIER type. There are no formal -linkage between these instances and provision for ObjectDescriptor -uniqueness in the standard. - -.. code-block:: pycon - - >>> from pyasn1.type import useful - >>> descrBER = useful.ObjectDescriptor( - "Basic encoding of a single ASN.1 type" - ) - >>> - -GeneralizedTime and UTCTime types are designed to hold a -human-readable timestamp in a universal and unambiguous form. The -former provides more flexibility in notation while the latter is more -strict but has Y2K issues. - -.. code-block:: bash - - ;; Mar 8 2010 12:00:00 MSK - moscow-time GeneralizedTime ::= "20110308120000.0" - ;; Mar 8 2010 12:00:00 UTC - utc-time GeneralizedTime ::= "201103081200Z" - ;; Mar 8 1999 12:00:00 UTC - utc-time UTCTime ::= "9803081200Z" - -In pyasn1 parlance: - -.. code-block:: pycon - - >>> from pyasn1.type import useful - >>> moscowTime = useful.GeneralizedTime("20110308120000.0") - >>> utcTime = useful.UTCTime("9803081200Z") - >>> - -Despite their intended use, these types possess no special, time-related, -handling in pyasn1. They are just printable strings. - -Tagging -------- - -In order to proceed to the Constructed ASN.1 types, we will first have -to introduce the concept of tagging (and its pyasn1 implementation), as -some of the Constructed types rely upon the tagging feature. - -When a value is coming into an ASN.1-based system (received from a network -or read from some storage), the receiving entity has to determine the -type of the value to interpret and verify it accordingly. - -Historically, the first data serialization protocol introduced in -ASN.1 was BER (Basic Encoding Rules). According to BER, any serialized -value is packed into a triplet of (Type, Length, Value) where Type is a -code that identifies the value (which is called *tag* in ASN.1), -length is the number of bytes occupied by the value in its serialized form -and value is ASN.1 value in a form suitable for serial transmission or storage. -For that reason almost every ASN.1 type has a tag (which is actually a -BER type) associated with it by default. - -An ASN.1 tag could be viewed as a tuple of three numbers: -(Class, Format, Number). While Number identifies a tag, Class component -is used to create scopes for Numbers. Four scopes are currently defined: -UNIVERSAL, context-specific, APPLICATION and PRIVATE. The Format component -is actually a one-bit flag - zero for tags associated with scalar types, -and one for constructed types (will be discussed later on). - -.. code-block:: bash - - MyIntegerType ::= [12] INTEGER - MyOctetString ::= [APPLICATION 0] OCTET STRING - -In pyasn1, tags are implemented as immutable, tuple-like objects: - -.. code-block:: pycon - - >>> from pyasn1.type import tag - >>> myTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) - >>> myTag - Tag(tagClass=128, tagFormat=0, tagId=10) - >>> tuple(myTag) - (128, 0, 10) - >>> myTag[2] - 10 - >>> myTag == tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 10) - False - >>> - -Default tag, associated with any ASN.1 type, could be extended or -replaced to make new type distinguishable from its ancestor. The -standard provides two modes of tag mangling - IMPLICIT and EXPLICIT. - -EXPLICIT mode works by appending new tag to the existing ones thus -creating an ordered set of tags. This set will be considered as a -whole for type identification and encoding purposes. Important -property of EXPLICIT tagging mode is that it preserves base type -information in encoding what makes it possible to completely recover -type information from encoding. - -When tagging in IMPLICIT mode, the outermost existing tag is dropped -and replaced with a new one. - -.. code-block:: bash - - MyIntegerType ::= [12] IMPLICIT INTEGER - MyOctetString ::= [APPLICATION 0] EXPLICIT OCTET STRING - -To model both modes of tagging, a specialized container TagSet object -(holding zero, one or more Tag objects) is used in pyasn1. - -.. code-block:: pycon - - >>> from pyasn1.type import tag - >>> tagSet = tag.TagSet( - ... # base tag (OBSOLETE AND NOT USED ANYMORE) - ... (), - ... # effective tag - ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) - ... ) - >>> tagSet - TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10)) - >>> tagSet.getBaseTag() - Tag(tagClass=128, tagFormat=0, tagId=10) - >>> tagSet = tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20)) - >>> tagSet - TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10), - Tag(tagClass=128, tagFormat=32, tagId=20)) - >>> tagSet = tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 30)) - >>> tagSet - TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10), - Tag(tagClass=128, tagFormat=32, tagId=20), - Tag(tagClass=128, tagFormat=32, tagId=30)) - >>> tagSet = tagSet.tagImplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)) - >>> tagSet - TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10), - Tag(tagClass=128, tagFormat=32, tagId=20), - Tag(tagClass=128, tagFormat=32, tagId=40)) - >>> - -As a side note: the "base tag" concept is now obsolete and not used. -The "effective tag" is the one that always appears in encoding and is -used on tagSets comparation. - -Any two TagSet objects could be compared to see if one is a derivative -of the other. Figuring this out is also useful in cases when a type-specific -data processing algorithms are to be chosen. - -.. code-block:: pycon - - >>> from pyasn1.type import tag - >>> tagSet1 = tag.TagSet( - ... # base tag (OBSOLETE AND NOT USED ANYMORE) - ... (), - ... # effective tag - ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) - ... ) - >>> tagSet2 = tagSet1.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20)) - >>> tagSet1.isSuperTagSetOf(tagSet2) - True - >>> tagSet2.isSuperTagSetOf(tagSet1) - False - >>> - -We will complete this discussion on tagging with a real-world example. The -following ASN.1 tagged type: - -.. code-block:: bash - - MyIntegerType ::= [12] EXPLICIT INTEGER - -could be expressed in pyasn1 like this: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, tag - >>> class MyIntegerType(univ.Integer): - ... tagSet = univ.Integer.tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12)) - >>> myInteger = MyIntegerType(12345) - >>> myInteger.tagSet - TagSet((), Tag(tagClass=0, tagFormat=0, tagId=2), - Tag(tagClass=128, tagFormat=32, tagId=12)) - >>> - -Referring to the above code, the tagSet class attribute is a property -of any pyasn1 type object that assigns default tagSet to a pyasn1 -value object. This default tagSet specification can be ignored and -effectively replaced by some other tagSet value passed on object -instantiation. - -It's important to understand that the tag set property of pyasn1 type/value -object can never be modifed in place. In other words, a pyasn1 type/value -object can never change its tags. The only way is to create a new pyasn1 -type/value object and associate different tag set with it. - -Constructed types ------------------ - -Besides scalar types, ASN.1 specifies so-called constructed ones - these -are capable of holding one or more values of other types, both scalar -and constructed. - -In pyasn1 implementation, constructed ASN.1 types behave like -Python sequences, and also support additional component addressing methods, -specific to particular constructed type. - -Sequence and Set types -++++++++++++++++++++++ - -The *SEQUENCE* and *SET* types have many similar properties: - -* Both can hold any number of inner components of different types. -* Every component has a human-friendly identifier. -* Any component can have a default value. -* Some components can be absent. - -However, :py:class:`~pyasn1.type.univ.Sequence` type guarantees the -ordering of Sequence value components to match their declaration -order. By contrast, components of the -:py:class:`~pyasn1.type.univ.Set` type can be ordered to best suite -application's needs. - -.. code-block:: bash - - Record ::= SEQUENCE { - id INTEGER, - room [0] INTEGER OPTIONAL, - house [1] INTEGER DEFAULT 0 - } - -Up to this moment, the only method we used for creating new pyasn1 -types is Python sub-classing. With this method, a new, named Python -class is created what mimics type derivation in ASN.1 grammar. -However, ASN.1 also allows for defining anonymous subtypes (room and -house components in the example above). To support anonymous -subtyping in pyasn1, a cloning operation on an existing pyasn1 type -object can be invoked what creates a new instance of original object -with possibly modified properties. - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedtype, tag - >>> class Record(univ.Sequence): - ... componentType = namedtype.NamedTypes( - ... namedtype.NamedType('id', univ.Integer()), - ... namedtype.OptionalNamedType( - ... 'room', - ... univ.Integer().subtype( - ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0) - ... ) - ... ), - ... namedtype.DefaultedNamedType( - ... 'house', - ... univ.Integer(0).subtype( - ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1) - ... ) - ... ) - ... ) - >>> - -All pyasn1 constructed type classes have a class attribute -**componentType** that represent default type specification. Its -value is a NamedTypes object. - -The NamedTypes class instance holds a sequence of NameType, -OptionalNamedType or DefaultedNamedType objects which, in turn, refer -to pyasn1 type objects that represent inner SEQUENCE components -specification. - -Finally, invocation of a subtype() method of pyasn1 type objects in -the code above returns an implicitly tagged copy of original object. - -Once a SEQUENCE or SET type is decleared with pyasn1, it can be -instantiated and initialized (continuing the above code): - -.. code-block:: pycon - - >>> record = Record() - >>> record['id'] = 123 - >>> print(record.prettyPrint()) - Record: - id=123 - >>> - >>> record[1] = 321 - >>> print(record.prettyPrint()) - Record: - id=123 - room=321 - >>> - >>> record.setDefaultComponents() - >>> print(record.prettyPrint()) - Record: - id=123 - room=321 - house=0 - -Inner components of pyasn1 Sequence/Set objects could be accessed -using the following methods: - -.. code-block:: pycon - - >>> record['id'] - Integer(123) - >>> record[1] - Integer(321) - >>> record[2] - Integer(0) - >>> for idx, field in enumerate(record): - ... print(record.componentType[idx].name, field) - id 123 - room 321 - house 0 - >>> - -The Set type share all the properties of Sequence type, and additionally -support by-tag component addressing (as all Set components have distinct -types). - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedtype, tag - >>> class Gamer(univ.Set): - ... componentType = namedtype.NamedTypes( - ... namedtype.NamedType('score', univ.Integer()), - ... namedtype.NamedType('player', univ.OctetString()), - ... namedtype.NamedType('id', univ.ObjectIdentifier()) - ... ) - >>> gamer = Gamer() - >>> gamer.setComponentByType(univ.Integer().tagSet, 121343) - >>> gamer.setComponentByType(univ.OctetString().tagSet, 'Pascal') - >>> gamer.setComponentByType(univ.ObjectIdentifier().tagSet, (1,3,7,2)) - >>> print(gamer.prettyPrint()) - Gamer: - score=121343 - player=b'Pascal' - id=1.3.7.2 - -SequenceOf and SetOf types -++++++++++++++++++++++++++ - -Both, *SEQUENCE OF* and *SET OF* types resemble an unlimited size list of -components. All the components must be of the same type. - -.. code-block:: bash - - Progression ::= SEQUENCE OF INTEGER - - arithmeticProgression Progression ::= { 1, 3, 5, 7 } - -:py:class:`~pyasn1.type.univ.SequenceOf` and -:py:class:`~pyasn1.type.univ.SetOf` types are expressed by the very -similar pyasn1 `list` type objects. Their components can only be addressed by -position and they both have a property of automatic resize. - -To specify inner component type, the **componentType** class -attribute should refer to another pyasn1 type object. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> class Progression(univ.SequenceOf): - ... componentType = univ.Integer() - >>> arithmeticProgression = Progression() - >>> arithmeticProgression[1] = 111 - >>> print(arithmeticProgression.prettyPrint()) - Progression: - -empty- 111 - >>> arithmeticProgression[0] = 100 - >>> print(arithmeticProgression.prettyPrint()) - Progression: - 100 111 - >>> - >>> for element in arithmeticProgression: - ... element - Integer(100) - Integer(111) - >>> - -Any scalar or constructed pyasn1 type object can serve as an inner -component. Missing components are prohibited in SequenceOf/SetOf -value objects. - -Choice type -+++++++++++ - -Values of ASN.1 *CHOICE* type can contain only a single value of a type -from a list of possible alternatives. Alternatives must be ASN.1 types -with distinct tags for the whole structure to remain unambiguous. -Unlike most other types, CHOICE is an untagged one, e.g. it has no -base tag of its own. - -.. code-block:: bash - - CodeOrMessage ::= CHOICE { - code INTEGER, - message OCTET STRING - } - -In pyasn1 implementation, -:py:class:`~pyasn1.type.univ.Choice` object behaves like Set but -accepts only a single inner component at a time. It also offers a few -additional methods specific to its behaviour. - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedtype - >>> class CodeOrMessage(univ.Choice): - ... componentType = namedtype.NamedTypes( - ... namedtype.NamedType('code', univ.Integer()), - ... namedtype.NamedType('message', univ.OctetString()) - ... ) - >>> - >>> codeOrMessage = CodeOrMessage() - >>> print(codeOrMessage.prettyPrint()) - CodeOrMessage: - >>> codeOrMessage['code'] = 123 - >>> print(codeOrMessage.prettyPrint()) - CodeOrMessage: - code=123 - >>> codeOrMessage['message'] = 'my string value' - >>> print(codeOrMessage.prettyPrint()) - CodeOrMessage: - message=b'my string value' - >>> - -Since there could be only a single inner component value in the pyasn1 -Choice value object, either of the following methods could be used for -fetching it (continuing previous code): - -.. code-block:: pycon - - >>> codeOrMessage.getName() - 'message' - >>> codeOrMessage.getComponent() - OctetString(b'my string value') - >>> - -Subtype constraints -------------------- - -Most ASN.1 types can correspond to an infinite set of values. To adapt -to particular application's data model and needs, ASN.1 provides a -mechanism for limiting the infinite set to values, that make sense in -particular case. Imposing value constraints on an ASN.1 type can also -be seen as creating a subtype from its base type. - -In pyasn1, constraints take shape of immutable objects capable -of evaluating given value against constraint-specific requirements. -Constraint object is a property of pyasn1 type. Like TagSet property, -associated with every pyasn1 type, constraints can never be modified -in place. The only way to modify pyasn1 type constraint is to associate -new constraint object to a new pyasn1 type object. - -A handful of different flavors of *constraints* are defined in -ASN.1. We will discuss them one by one in the following chapters and -also explain how to combine and apply them to types. - -Single value constraint -+++++++++++++++++++++++ - -This kind of constraint allows for limiting type to a finite, specified set -of values. - -.. code-block:: bash - - DialButton ::= OCTET STRING ( - "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" - ) - -Its pyasn1 implementation would look like: - -.. code-block:: pycon - - >>> from pyasn1.type import constraint - >>> c = constraint.SingleValueConstraint('0','1','2','3','4','5','6','7','8','9') - >>> c - SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) - >>> c('0') - >>> c('A') - Traceback (most recent call last): - ... - ValueConstraintError: - SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A - >>> - -As can be seen in the snippet above, if a value violates the -constraint, an exception will be thrown. A constrainted pyasn1 type -object holds a reference to a constraint object (or their combination, -as will be explained later) and calls it for value verification. - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> class DialButton(univ.OctetString): - ... subtypeSpec = constraint.SingleValueConstraint( - ... '0','1','2','3','4','5','6','7','8','9' - ... ) - >>> DialButton('0') - DialButton(b'0') - >>> DialButton('A') - Traceback (most recent call last): - ... - ValueConstraintError: - SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A - >>> - -Constrained pyasn1 value object can never hold a violating value. - -Value range constraint -++++++++++++++++++++++ - -A pair of values, compliant to a type to be constrained, denote low -and upper bounds of allowed range of values of a type. - -.. code-block:: bash - - Teenagers ::= INTEGER (13..19) - -And in pyasn1 terms: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> class Teenagers(univ.Integer): - ... subtypeSpec = constraint.ValueRangeConstraint(13, 19) - >>> Teenagers(14) - Teenagers(14) - >>> Teenagers(20) - Traceback (most recent call last): - ... - ValueConstraintError: - ValueRangeConstraint(13, 19) failed at: 20 - >>> - -ASN.1 MIN and MAX operands can be substituted with floating point -infinity values. - -.. code-block:: bash - - NegativeInt ::= INTEGER (MIN..-1) - PositiveInt ::= INTEGER (1..MAX) - -And in pyasn1 terms: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> class NegativeInt(univ.Integer): - ... subtypeSpec = constraint.ValueRangeConstraint(float('-inf'), -1) - >>> NegativeInt(-1) - NegativeInt(-1) - >>> NegativeInt(0) - Traceback (most recent call last): - ... - ValueConstraintError: - ValueConstraintError: ValueRangeConstraint() failed at: "0" at NegativeInt - >>> class PositiveInt(univ.Integer): - ... subtypeSpec = constraint.ValueRangeConstraint(1, float('inf')) - >> PositiveInt(1) - PositiveInt(1) - >> PositiveInt(4) - PositiveInt(4) - >> PositiveInt(-1) - Traceback (most recent call last): - ... - ValueConstraintError: - ValueConstraintError: ValueRangeConstraint() failed at: "-1" at PositiveInt - -Value range constraint usually applies to numeric types. - -Size constraint -+++++++++++++++ - -It is sometimes convenient to set or limit the allowed size of a data -item to be sent from one application to another to manage bandwidth -and memory consumption issues. Size constraint specifies the lower and -upper bounds of the size of a valid value. - -.. code-block:: bash - - TwoBits ::= BIT STRING (SIZE (2)) - -Express the same grammar in pyasn1: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> class TwoBits(univ.BitString): - ... subtypeSpec = constraint.ValueSizeConstraint(2, 2) - >>> TwoBits((1,1)) - TwoBits("'11'B") - >>> TwoBits((1,1,0)) - Traceback (most recent call last): - ... - ValueConstraintError: ValueSizeConstraint(2, 2) failed at: (1, 1, 0) - >>> - -Size constraint can be applied to potentially massive values - bit or -octet strings, SEQUENCE OF/SET OF values. - -Alphabet constraint -+++++++++++++++++++ - -The permitted alphabet constraint is similar to Single value -constraint but constraint applies to individual characters of a value. - -.. code-block:: bash - - MorseCode ::= PrintableString (FROM ("."|"-"|" ")) - -And in pyasn1: - -.. code-block:: pycon - - >>> from pyasn1.type import char, constraint - >>> class MorseCode(char.PrintableString): - ... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ") - >>> MorseCode("...---...") - MorseCode('...---...') - >>> MorseCode("?") - Traceback (most recent call last): - ... - ValueConstraintError: PermittedAlphabetConstraint(".", "-", " ") failed at: "?" - >>> - -Current implementation does not handle ranges of characters in -constraint (FROM "A".."Z" syntax), one has to list the whole set in a -range. - -Constraint combinations -+++++++++++++++++++++++ - -Up to this moment, we used a single constraint per ASN.1 type. The -standard, however, allows for combining multiple individual -constraints into intersections, unions and exclusions. - -In pyasn1 data model, all of these methods of constraint combinations -are implemented as constraint-like objects holding individual -constraint (or combination) objects. Like terminal constraint objects, -combination objects are capable to perform value verification at its -set of enclosed constraints according to the logic of particular -combination. - -Constraints intersection verification succeeds only if a value is -compliant to each constraint in a set. To begin with, the following -specification will constitute a valid telephone number: - -.. code-block:: bash - - PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11) - -Constraint intersection object serves the logic above: - -.. code-block:: pycon - - >>> from pyasn1.type import char, constraint - >>> class PhoneNumber(char.NumericString): - ... subtypeSpec = constraint.ConstraintsIntersection( - ... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6', '7','8','9'), - ... constraint.ValueSizeConstraint(11, 11) - ... ) - >>> PhoneNumber('79039343212') - PhoneNumber('79039343212') - >>> PhoneNumber('?9039343212') - Traceback (most recent call last): - ... - ValueConstraintError: ConstraintsIntersection(PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), ValueSizeConstraint(11, 11)) failed at: PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212" - >>> PhoneNumber('9343212') - Traceback (most recent call last): - ... - ValueConstraintError: - ConstraintsIntersection(PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), ValueSizeConstraint(11, 11)) failed at: ValueSizeConstraint(10, 10) failed at: "9343212" - >>> - -Union of constraints works by making sure that a value is compliant -to any of the constraint in a set. For instance: - -.. code-block:: bash - - CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c')) - -It's important to note, that a value must fully comply to any single -constraint in a set. In the specification above, a value of all small -or all capital letters is compliant, but a mix of small&capitals is -not. Here's its pyasn1 analogue: - -.. code-block:: pycon - - >>> from pyasn1.type import char, constraint - >>> class CapitalOrSmall(char.IA5String): - ... subtypeSpec = constraint.ConstraintsUnion( - ... constraint.PermittedAlphabetConstraint('A','B','C'), - ... constraint.PermittedAlphabetConstraint('a','b','c') - ... ) - >>> CapitalOrSmall('ABBA') - CapitalOrSmall('ABBA') - >>> CapitalOrSmall('abba') - CapitalOrSmall('abba') - >>> CapitalOrSmall('Abba') - Traceback (most recent call last): - ... - ValueConstraintError: ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'), PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba" - >>> - -Finally, the exclusion constraint simply negates the logic of value -verification at a constraint. In the following example, any integer -value is allowed in a type but not zero. - -.. code-block:: bash - - NoZero ::= INTEGER (ALL EXCEPT 0) - -In pyasn1 the above definition would read: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> class NoZero(univ.Integer): - ... subtypeSpec = constraint.ConstraintsExclusion( - ... constraint.SingleValueConstraint(0) - ... ) - >>> NoZero(1) - NoZero(1) - >>> NoZero(0) - Traceback (most recent call last): - ... - ValueConstraintError: ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0 - >>> - -The depth of such a constraints tree, built with constraint -combination objects at its nodes, has not explicit limit. Value -verification is performed in a recursive manner till a definite -solution is found. - -Types relationships -+++++++++++++++++++ - -In the course of data processing in an application, it is sometimes -convenient to figure out the type relationships between pyasn1 type or -value objects. Formally, two things influence pyasn1 types -relationship: *tag set* and *subtype constraints*. One -pyasn1 type is considered to be a derivative of another if their -TagSet and Constraint objects are a derivation of one another. - -The following example illustrates the concept (we use the same tagset -but different constraints for simplicity): - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8)) - >>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection( - ... constraint.ValueRangeConstraint(3,8), - ... constraint.ValueRangeConstraint(4,7) - ... ) ) - >>> i1.isSameTypeWith(i2) - False - >>> i1.isSuperTypeOf(i2) - True - >>> i1.isSuperTypeOf(i1) - True - >>> i2.isSuperTypeOf(i1) - False - >>> - -As can be seen in the above code snippet, there are two methods of any -pyasn1 type/value object that test types for their relationship: -*isSameTypeWith()* and *isSuperTypeOf()*. The former is -self-descriptive while the latter yields true if the argument appears -to be a pyasn1 object which has tagset and constraints derived from -those of the object being called. - -Serialization codecs --------------------- - -In ASN.1 context, `codec <http://en.wikipedia.org/wiki/Codec>`_ -is a program that transforms between concrete data structures and a stream -of octets, suitable for transmission over the wire. This serialized form of -data is sometimes called *substrate* or *essence*. - -In pyasn1 implementation, substrate takes shape of Python 3 bytes or -Python 2 string objects. - -One of the properties of a codec is its ability to cope with -incomplete data and/or substrate what implies codec to be stateful. In -other words, when decoder runs out of substrate and data item being -recovered is still incomplete, stateful codec would suspend and -complete data item recovery whenever the rest of substrate becomes -available. Similarly, stateful encoder would encode data items in -multiple steps waiting for source data to arrive. Codec restartability -is especially important when application deals with large volumes of -data and/or runs on low RAM. For an interesting discussion on codecs -options and design choices, refer to `Apache ASN.1 project -<http://directory.apache.org/subprojects/asn1/>`_ . - -As of this writing, codecs implemented in pyasn1 are all stateless, -mostly to keep the code simple. - -The pyasn1 package currently supports -`BER <http://en.wikipedia.org/wiki/Basic_encoding_rules>`_ codec and -its variations -- -`CER <http://en.wikipedia.org/wiki/Canonical_encoding_rules>`_ and -`DER <http://en.wikipedia.org/wiki/Distinguished_encoding_rules>`_. -More ASN.1 codecs are planned for implementation in the future. - -Encoders -++++++++ - -Encoder is used for transforming pyasn1 value objects into substrate. -Only pyasn1 value objects could be serialized, attempts to process -pyasn1 type objects will cause encoder failure. - -The following code will create a pyasn1 Integer object and serialize -it with BER encoder: - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder - >>> encoder.encode(univ.Integer(123456)) - b'\x02\x03\x01\xe2@' - >>> - -BER standard also defines a so-called *indefinite length* -encoding form which makes large data items processing more memory -efficient. It is mostly useful when encoder does not have the whole -value all at once and the length of the value can not be determined at -the beginning of encoding. - -*Constructed encoding* is another feature of BER closely related to -the indefinite length form. In essence, a large scalar value (such as -ASN.1 character BitString type) could be chopped into smaller chunks -by encoder and transmitted incrementally to limit memory consumption. -Unlike indefinite length case, the length of the whole value must be -known in advance when using constructed, definite length encoding -form. - -Since pyasn1 codecs are not restartable, pyasn1 encoder may only -encode data item all at once. However, even in this case, generating -indefinite length encoding may help a low-memory receiver, running a -restartable decoder, to process a large data item. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder - >>> encoder.encode( - ... univ.OctetString('The quick brown fox jumps over the lazy dog'), - ... defMode=False, - ... maxChunkSize=8 - ... ) - b'$\x80\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \t\x04\x08he lazy \x04\x03dog\x00\x00' - >>> - >>> encoder.encode( - ... univ.OctetString('The quick brown fox jumps over the lazy dog'), - ... maxChunkSize=8 - ... ) - b'$7\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \t\x04\x08he lazy \x04\x03dog' - -The *defMode* encoder parameter disables definite length encoding -mode, while the optional *maxChunkSize* parameter specifies desired -substrate chunk size that influences memory requirements at the -decoder's end. - -To use CER or DER encoders one needs to explicitly import and call them - the -APIs are all compatible. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder as ber_encoder - >>> from pyasn1.codec.cer import encoder as cer_encoder - >>> from pyasn1.codec.der import encoder as der_encoder - >>> ber_encoder.encode(univ.Boolean(True)) - b'\x01\x01\x01' - >>> cer_encoder.encode(univ.Boolean(True)) - b'\x01\x01\xff' - >>> der_encoder.encode(univ.Boolean(True)) - b'\x01\x01\xff' - >>> - -Decoders -++++++++ - -In the process of decoding, pyasn1 value objects are created and -linked to each other, based on the information containted in the -substrate. Thus, the original pyasn1 value object(s) are recovered. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder, decoder - >>> substrate = encoder.encode(univ.Boolean(True)) - >>> decoder.decode(substrate) - (Boolean('True(1)'), b'') - >>> - -Commenting on the code snippet above, pyasn1 decoder accepts substrate -as an argument and returns a tuple of pyasn1 value object (possibly a -top-level one in case of constructed object) and unprocessed part of -input substrate. - -All pyasn1 decoders can handle both definite and indefinite length -encoding modes automatically, explicit switching into one mode to -another is not required. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder, decoder - >>> substrate = encoder.encode( - ... univ.OctetString('The quick brown fox jumps over the lazy dog'), - ... defMode=False, - ... maxChunkSize=8 - ... ) - >>> decoder.decode(substrate) - (OctetString(b'The quick brown fox jumps over the lazy dog'), b'') - >>> - -Speaking of BER/CER/DER encoding, in many situations substrate may not -contain all necessary information needed for complete and accurate -ASN.1 values recovery. The most obvious cases include implicitly -tagged ASN.1 types and constrained types. - -As discussed earlier in this tutorial, when an ASN.1 type is implicitly -tagged, previous outermost tag is lost and never appears in substrate. -If it is the base tag that gets lost, decoder is unable to pick type-specific -value decoder at its table of built-in types, and therefore recover -the value part, based only on the information contained in substrate. The -approach taken by pyasn1 decoder is to use a prototype pyasn1 type object (or -a set of them) to *guide* the decoding process by matching [possibly -incomplete] tags recovered from substrate with those found in prototype pyasn1 -type objects (also called pyasn1 specification object further in this -document). - -.. code-block:: pycon - - >>> from pyasn1.codec.ber import decoder - >>> decoder.decode(b'\x02\x01\x0c', asn1Spec=univ.Integer()) - Integer(12), b'' - >>> - -Decoder would neither modify pyasn1 specification object nor use its -current values (if it's a pyasn1 value object), but rather use it as a -hint for choosing proper decoder and as a pattern for creating new -objects: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, tag - >>> from pyasn1.codec.ber import encoder, decoder - >>> i = univ.Integer(12345).subtype( - ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40) - ... ) - >>> substrate = encoder.encode(i) - >>> substrate - b'\x9f(\x0209' - >>> decoder.decode(substrate) - Traceback (most recent call last): - ... - pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) not in asn1Spec - >>> decoder.decode(substrate, asn1Spec=i) - (Integer(12345), b'') - >>> - -Notice in the example above, that an attempt to run decoder without -passing pyasn1 specification object fails because recovered tag does -not belong to any of the built-in types. - -Another important feature of guided decoder operation is the use of -values constraints possibly present in pyasn1 specification object. -To explain this, we will decode a random integer object into generic Integer -and the constrained one. - -.. code-block:: pycon - - >>> from pyasn1.type import univ, constraint - >>> from pyasn1.codec.ber import encoder, decoder - >>> class DialDigit(univ.Integer): - ... subtypeSpec = constraint.ValueRangeConstraint(0,9) - >>> substrate = encoder.encode(univ.Integer(13)) - >>> decoder.decode(substrate) - (Integer(13), b'') - >>> decoder.decode(substrate, asn1Spec=DialDigit()) - Traceback (most recent call last): - ... - ValueConstraintError: - ValueRangeConstraint(0, 9) failed at: 13 - >>> - -Similarily to encoders, to use CER or DER decoders application has to -explicitly import and call them - all APIs are compatible. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder as ber_encoder - >>> substrate = ber_encoder.encode(univ.OctetString('http://pyasn1.sf.net')) - >>> - >>> from pyasn1.codec.ber import decoder as ber_decoder - >>> from pyasn1.codec.cer import decoder as cer_decoder - >>> from pyasn1.codec.der import decoder as der_decoder - >>> - >>> ber_decoder.decode(substrate) - (OctetString(b'http://pyasn1.sf.net'), b'') - >>> cer_decoder.decode(substrate) - (OctetString(b'http://pyasn1.sf.net'), b'') - >>> der_decoder.decode(substrate) - (OctetString(b'http://pyasn1.sf.net'), b'') - >>> - -Advanced topics ---------------- - -Certain, non-trivial, ASN.1 data structures may require special -treatment, especially when running deserialization. - -Decoding untagged types -+++++++++++++++++++++++ - -It has already been mentioned, that ASN.1 has two "special case" -types: CHOICE and ANY. They are different from other types in part of -tagging - unless these two are additionally tagged, neither of them -will have their own tag. Therefore these types become invisible in -substrate and can not be recovered without passing pyasn1 -specification object to decoder. - -To explain the issue, we will first prepare a Choice object to deal with: - -.. code-block:: pycon - - >>> from pyasn1.type import univ, namedtype - >>> class CodeOrMessage(univ.Choice): - ... componentType = namedtype.NamedTypes( - ... namedtype.NamedType('code', univ.Integer()), - ... namedtype.NamedType('message', univ.OctetString()) - ... ) - >>> - >>> codeOrMessage = CodeOrMessage() - >>> codeOrMessage['message'] = 'my string value' - >>> print(codeOrMessage.prettyPrint()) - CodeOrMessage: - message=b'my string value' - >>> - -Let's now encode this Choice object and then decode its substrate -with and without pyasn1 specification object: - -.. code-block:: pycon - - >>> from pyasn1.codec.ber import encoder, decoder - >>> substrate = encoder.encode(codeOrMessage) - >>> substrate - b'\x04\x0fmy string value' - >>> encoder.encode(univ.OctetString('my string value')) - b'\x04\x0fmy string value' - >>> - >>> decoder.decode(substrate) - (OctetString(b'my string value'), b'') - >>> codeOrMessage, substrate = decoder.decode(substrate, - asn1Spec=CodeOrMessage()) - >>> print(codeOrMessage.prettyPrint()) - CodeOrMessage: - message=b'my string value' - >>> - -First thing to notice in the listing above is that the substrate -produced for our Choice value object is equivalent to the substrate -for an OctetString object initialized to the same value. In other -words, any information about the Choice component is absent in -encoding. - -Sure enough, that kind of substrate will decode into an OctetString -object, unless original Choice type object is passed to decoder to -guide the decoding process. - -Similarily untagged ANY type behaves differently on decoding phase - -when decoder bumps into an Any object in pyasn1 specification, it -stops decoding and puts all the substrate into a new Any value object -in form of an octet string. Concerned application could then re-run -decoder with an additional, more exact pyasn1 specification object to -recover the contents of Any object. - -As it was mentioned elsewhere in this documentation, Any type allows -for incomplete or changing ASN.1 specification to be handled -gracefully by decoder and applications. - -To illustrate the working of Any type, we'll have to make the stage by -encoding a pyasn1 object and then putting its substrate into an any -object. - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder, decoder - >>> innerSubstrate = encoder.encode(univ.Integer(1234)) - >>> innerSubstrate - b'\x02\x02\x04\xd2' - >>> any = univ.Any(innerSubstrate) - >>> any - Any(b'\x02\x02\x04\xd2') - >>> substrate = encoder.encode(any) - >>> substrate - b'\x02\x02\x04\xd2' - >>> - -As with Choice type encoding, there is no traces of Any type in -substrate. Obviously, the substrate we are dealing with, will decode -into the inner [Integer] component, unless pyasn1 specification is -given to guide the decoder. Continuing previous code: - -.. code-block:: pycon - - >>> from pyasn1.type import univ - >>> from pyasn1.codec.ber import encoder, decoder - - >>> decoder.decode(substrate) - (Integer(1234), b'') - >>> any, substrate = decoder.decode(substrate, asn1Spec=univ.Any()) - >>> any - Any(b'\x02\x02\x04\xd2') - >>> decoder.decode(str(any)) - (Integer(1234), b'') - >>> - -Both CHOICE and ANY types are widely used in practice. Reader is welcome to -take a look at -`ASN.1 specifications of X.509 applications -<http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt>`_ -for more information. - -Ignoring unknown types -++++++++++++++++++++++ - -When dealing with a loosely specified ASN.1 structure, the receiving -end may not be aware of some types present in the substrate. It may be -convenient then to turn decoder into a recovery mode. Whilst there, -decoder will not bail out when hit an unknown tag but rather treat it -as an Any type. - -.. code-block:: pycon - - >>> from pyasn1.type import univ, tag - >>> from pyasn1.codec.ber import encoder, decoder - >>> taggedInt = univ.Integer(12345).subtype( - ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40) - ... ) - >>> substrate = encoder.encode(taggedInt) - >>> decoder.decode(substrate) - Traceback (most recent call last): - ... - pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) - not in asn1Spec - >>> - >>> decoder.decode.defaultErrorState = decoder.stDumpRawValue - >>> decoder.decode(substrate) - (Any(b'\x9f(\x0209'), '') - >>> - -It's also possible to configure a custom decoder, to handle unknown -tags found in substrate. This can be done by means of -*defaultRawDecoder* attribute holding a reference to type decoder -object. Refer to the source for API details. diff --git a/doc/source/docs/type/char/contents.rst b/doc/source/docs/type/char/contents.rst deleted file mode 100644 index ec01d93..0000000 --- a/doc/source/docs/type/char/contents.rst +++ /dev/null @@ -1,20 +0,0 @@ - -Character types ---------------- - -.. toctree:: - :maxdepth: 2 - - /docs/type/char/numericstring - /docs/type/char/printablestring - /docs/type/char/teletexstring - /docs/type/char/t61string - /docs/type/char/videotexstring - /docs/type/char/ia5string - /docs/type/char/graphicstring - /docs/type/char/visiblestring - /docs/type/char/iso646string - /docs/type/char/generalstring - /docs/type/char/universalstring - /docs/type/char/bmpstring - /docs/type/char/utf8string diff --git a/doc/source/docs/type/namedtype/contents.rst b/doc/source/docs/type/namedtype/contents.rst deleted file mode 100644 index 57bdc5c..0000000 --- a/doc/source/docs/type/namedtype/contents.rst +++ /dev/null @@ -1,11 +0,0 @@ - -Fields of constructed types ---------------------------- - -.. toctree:: - :maxdepth: 2 - - /docs/type/namedtype/namedtype - /docs/type/namedtype/optionalnamedtype - /docs/type/namedtype/defaultednamedtype - /docs/type/namedtype/namedtypes diff --git a/doc/source/docs/type/tag/contents.rst b/doc/source/docs/type/tag/contents.rst deleted file mode 100644 index 955412a..0000000 --- a/doc/source/docs/type/tag/contents.rst +++ /dev/null @@ -1,10 +0,0 @@ - -Tagging types -------------- - -.. toctree:: - :maxdepth: 2 - - /docs/type/tag/tag - /docs/type/tag/tagset - /docs/type/tag/tagmap diff --git a/doc/source/docs/type/univ/contents.rst b/doc/source/docs/type/univ/contents.rst deleted file mode 100644 index d0f8732..0000000 --- a/doc/source/docs/type/univ/contents.rst +++ /dev/null @@ -1,23 +0,0 @@ - -Universal types ---------------- - -.. autoclass:: pyasn1.type.univ.NoValue() - -.. toctree:: - :maxdepth: 2 - - /docs/type/univ/integer - /docs/type/univ/boolean - /docs/type/univ/bitstring - /docs/type/univ/octetstring - /docs/type/univ/null - /docs/type/univ/objectidentifier - /docs/type/univ/real - /docs/type/univ/enumerated - /docs/type/univ/any - /docs/type/univ/setof - /docs/type/univ/sequenceof - /docs/type/univ/set - /docs/type/univ/sequence - /docs/type/univ/choice diff --git a/doc/source/docs/type/useful/contents.rst b/doc/source/docs/type/useful/contents.rst deleted file mode 100644 index c8db8af..0000000 --- a/doc/source/docs/type/useful/contents.rst +++ /dev/null @@ -1,10 +0,0 @@ - -Useful types ------------- - -.. toctree:: - :maxdepth: 2 - - /docs/type/useful/objectdescriptor - /docs/type/useful/generalizedtime - /docs/type/useful/utctime diff --git a/doc/Makefile b/docs/Makefile index 214532e..214532e 100644 --- a/doc/Makefile +++ b/docs/Makefile diff --git a/doc/source/.static/css/rtdimproved.css b/docs/source/.static/css/rtdimproved.css index 981f84e..981f84e 100644 --- a/doc/source/.static/css/rtdimproved.css +++ b/docs/source/.static/css/rtdimproved.css diff --git a/doc/source/changelog.rst b/docs/source/changelog.rst index 095fc83..095fc83 100644 --- a/doc/source/changelog.rst +++ b/docs/source/changelog.rst diff --git a/doc/source/conf.py b/docs/source/conf.py index 258e74b..e6616cb 100644 --- a/doc/source/conf.py +++ b/docs/source/conf.py @@ -12,9 +12,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os -import shlex # 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 @@ -52,7 +50,7 @@ source_suffix = '.rst' master_doc = 'contents' # General information about the project. -project = u'PyASN1' +project = u'ASN.1 Library for Python' # noinspection PyShadowingBuiltins copyright = u'2005-2017, Ilya Etingof <etingof@gmail.com>' author = u'Ilya Etingof <etingof@gmail.com>' @@ -114,8 +112,7 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -# html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' +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 diff --git a/doc/source/contents.rst b/docs/source/contents.rst index 66d2507..f2955a1 100644 --- a/doc/source/contents.rst +++ b/docs/source/contents.rst @@ -3,7 +3,7 @@ ASN.1 library for Python ======================== .. toctree:: - :maxdepth: 2 + :maxdepth: 3 Abstract Syntax Notation One (`ASN.1 <http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_1x>`_) is a @@ -82,8 +82,8 @@ 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. -Library capabilities --------------------- +Library documentation +--------------------- As of this moment, pyasn1 library implements all ASN.1 data types as Python objects in accordance with X.208 standard. Later, @@ -103,20 +103,16 @@ Both `pyasn1 <https://github.com/etingof/pyasn1>`_ and can be used out-of-the-box with Python versions 2.4 through 3.6. No external dependencies required. -Documentation -------------- - .. toctree:: - :maxdepth: 2 + :maxdepth: 3 - /docs/tutorial - /docs/api-reference + /pyasn1/contents Use case -------- .. toctree:: - :maxdepth: 2 + :maxdepth: 3 /example-use-case diff --git a/doc/source/example-use-case.rst b/docs/source/example-use-case.rst index d5be0cd..d5be0cd 100644 --- a/doc/source/example-use-case.rst +++ b/docs/source/example-use-case.rst diff --git a/doc/source/license.rst b/docs/source/license.rst index 643baf1..643baf1 100644 --- a/doc/source/license.rst +++ b/docs/source/license.rst diff --git a/doc/source/docs/codec/ber/contents.rst b/docs/source/pyasn1/codec/ber/contents.rst index 9f15a94..c767625 100644 --- a/doc/source/docs/codec/ber/contents.rst +++ b/docs/source/pyasn1/codec/ber/contents.rst @@ -2,6 +2,6 @@ Basic Encoding Rules -------------------- -.. autofunction:: pyasn1.codec.ber.encoder.encode(value, defMode=True, maxChunkSize=0) +.. autofunction:: pyasn1.codec.ber.encoder.encode(value, asn1Spec=None, defMode=True, maxChunkSize=0) .. autofunction:: pyasn1.codec.ber.decoder.decode(substrate, asn1Spec=None) diff --git a/doc/source/docs/codec/cer/contents.rst b/docs/source/pyasn1/codec/cer/contents.rst index 58b46da..8eec842 100644 --- a/doc/source/docs/codec/cer/contents.rst +++ b/docs/source/pyasn1/codec/cer/contents.rst @@ -2,6 +2,6 @@ Canonical Encoding Rules ------------------------ -.. autofunction:: pyasn1.codec.cer.encoder.encode(value) +.. autofunction:: pyasn1.codec.cer.encoder.encode(value, asn1Spec=None) .. autofunction:: pyasn1.codec.cer.decoder.decode(substrate, asn1Spec=None) diff --git a/doc/source/docs/codec/der/contents.rst b/docs/source/pyasn1/codec/der/contents.rst index dddee8e..27ef401 100644 --- a/doc/source/docs/codec/der/contents.rst +++ b/docs/source/pyasn1/codec/der/contents.rst @@ -2,6 +2,6 @@ Distinguished Encoding Rules ---------------------------- -.. autofunction:: pyasn1.codec.der.encoder.encode(value) +.. autofunction:: pyasn1.codec.der.encoder.encode(value, asn1Spec=None) .. autofunction:: pyasn1.codec.der.decoder.decode(substrate, asn1Spec=None) diff --git a/doc/source/docs/codec/native/contents.rst b/docs/source/pyasn1/codec/native/contents.rst index 11e96f0..11e96f0 100644 --- a/doc/source/docs/codec/native/contents.rst +++ b/docs/source/pyasn1/codec/native/contents.rst diff --git a/docs/source/pyasn1/contents.rst b/docs/source/pyasn1/contents.rst new file mode 100644 index 0000000..5d58a4f --- /dev/null +++ b/docs/source/pyasn1/contents.rst @@ -0,0 +1,26 @@ + + +ASN.1 types +----------- + +.. toctree:: + :maxdepth: 2 + + /pyasn1/type/univ/contents + /pyasn1/type/char/contents + /pyasn1/type/useful/contents + /pyasn1/type/tag/contents + /pyasn1/type/namedtype/contents + /pyasn1/type/opentype/contents + /pyasn1/type/namedval/contents + +Serialisation codecs +-------------------- + +.. toctree:: + :maxdepth: 2 + + /pyasn1/codec/ber/contents + /pyasn1/codec/cer/contents + /pyasn1/codec/der/contents + /pyasn1/codec/native/contents diff --git a/doc/source/docs/type/char/bmpstring.rst b/docs/source/pyasn1/type/char/bmpstring.rst index 3809e9b..3809e9b 100644 --- a/doc/source/docs/type/char/bmpstring.rst +++ b/docs/source/pyasn1/type/char/bmpstring.rst diff --git a/docs/source/pyasn1/type/char/contents.rst b/docs/source/pyasn1/type/char/contents.rst new file mode 100644 index 0000000..ddfbe1c --- /dev/null +++ b/docs/source/pyasn1/type/char/contents.rst @@ -0,0 +1,20 @@ + +Character types +--------------- + +.. 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 diff --git a/doc/source/docs/type/char/generalstring.rst b/docs/source/pyasn1/type/char/generalstring.rst index 8ce730f..8ce730f 100644 --- a/doc/source/docs/type/char/generalstring.rst +++ b/docs/source/pyasn1/type/char/generalstring.rst diff --git a/doc/source/docs/type/char/graphicstring.rst b/docs/source/pyasn1/type/char/graphicstring.rst index 1f57209..1f57209 100644 --- a/doc/source/docs/type/char/graphicstring.rst +++ b/docs/source/pyasn1/type/char/graphicstring.rst diff --git a/doc/source/docs/type/char/ia5string.rst b/docs/source/pyasn1/type/char/ia5string.rst index 1ae80af..1ae80af 100644 --- a/doc/source/docs/type/char/ia5string.rst +++ b/docs/source/pyasn1/type/char/ia5string.rst diff --git a/doc/source/docs/type/char/iso646string.rst b/docs/source/pyasn1/type/char/iso646string.rst index f21836a..f21836a 100644 --- a/doc/source/docs/type/char/iso646string.rst +++ b/docs/source/pyasn1/type/char/iso646string.rst diff --git a/doc/source/docs/type/char/numericstring.rst b/docs/source/pyasn1/type/char/numericstring.rst index dc805e4..dc805e4 100644 --- a/doc/source/docs/type/char/numericstring.rst +++ b/docs/source/pyasn1/type/char/numericstring.rst diff --git a/doc/source/docs/type/char/printablestring.rst b/docs/source/pyasn1/type/char/printablestring.rst index 22ebe28..22ebe28 100644 --- a/doc/source/docs/type/char/printablestring.rst +++ b/docs/source/pyasn1/type/char/printablestring.rst diff --git a/doc/source/docs/type/char/t61string.rst b/docs/source/pyasn1/type/char/t61string.rst index ed9d61e..ed9d61e 100644 --- a/doc/source/docs/type/char/t61string.rst +++ b/docs/source/pyasn1/type/char/t61string.rst diff --git a/doc/source/docs/type/char/teletexstring.rst b/docs/source/pyasn1/type/char/teletexstring.rst index 86aa248..86aa248 100644 --- a/doc/source/docs/type/char/teletexstring.rst +++ b/docs/source/pyasn1/type/char/teletexstring.rst diff --git a/doc/source/docs/type/char/universalstring.rst b/docs/source/pyasn1/type/char/universalstring.rst index e3159dc..e3159dc 100644 --- a/doc/source/docs/type/char/universalstring.rst +++ b/docs/source/pyasn1/type/char/universalstring.rst diff --git a/doc/source/docs/type/char/utf8string.rst b/docs/source/pyasn1/type/char/utf8string.rst index ddeeebf..ddeeebf 100644 --- a/doc/source/docs/type/char/utf8string.rst +++ b/docs/source/pyasn1/type/char/utf8string.rst diff --git a/doc/source/docs/type/char/videotexstring.rst b/docs/source/pyasn1/type/char/videotexstring.rst index 0570471..0570471 100644 --- a/doc/source/docs/type/char/videotexstring.rst +++ b/docs/source/pyasn1/type/char/videotexstring.rst diff --git a/doc/source/docs/type/char/visiblestring.rst b/docs/source/pyasn1/type/char/visiblestring.rst index b895eb5..b895eb5 100644 --- a/doc/source/docs/type/char/visiblestring.rst +++ b/docs/source/pyasn1/type/char/visiblestring.rst diff --git a/docs/source/pyasn1/type/namedtype/contents.rst b/docs/source/pyasn1/type/namedtype/contents.rst new file mode 100644 index 0000000..a5618e5 --- /dev/null +++ b/docs/source/pyasn1/type/namedtype/contents.rst @@ -0,0 +1,11 @@ + +Fields of constructed types +--------------------------- + +.. toctree:: + :maxdepth: 2 + + /pyasn1/type/namedtype/namedtype + /pyasn1/type/namedtype/optionalnamedtype + /pyasn1/type/namedtype/defaultednamedtype + /pyasn1/type/namedtype/namedtypes diff --git a/doc/source/docs/type/namedtype/defaultednamedtype.rst b/docs/source/pyasn1/type/namedtype/defaultednamedtype.rst index 9a331dc..9a331dc 100644 --- a/doc/source/docs/type/namedtype/defaultednamedtype.rst +++ b/docs/source/pyasn1/type/namedtype/defaultednamedtype.rst diff --git a/doc/source/docs/type/namedtype/namedtype.rst b/docs/source/pyasn1/type/namedtype/namedtype.rst index ea978ef..ea978ef 100644 --- a/doc/source/docs/type/namedtype/namedtype.rst +++ b/docs/source/pyasn1/type/namedtype/namedtype.rst diff --git a/doc/source/docs/type/namedtype/namedtypes.rst b/docs/source/pyasn1/type/namedtype/namedtypes.rst index fa8234d..fa8234d 100644 --- a/doc/source/docs/type/namedtype/namedtypes.rst +++ b/docs/source/pyasn1/type/namedtype/namedtypes.rst diff --git a/doc/source/docs/type/namedtype/optionalnamedtype.rst b/docs/source/pyasn1/type/namedtype/optionalnamedtype.rst index 8655a1e..8655a1e 100644 --- a/doc/source/docs/type/namedtype/optionalnamedtype.rst +++ b/docs/source/pyasn1/type/namedtype/optionalnamedtype.rst diff --git a/doc/source/docs/type/namedval/contents.rst b/docs/source/pyasn1/type/namedval/contents.rst index 3e5e830..169da15 100644 --- a/doc/source/docs/type/namedval/contents.rst +++ b/docs/source/pyasn1/type/namedval/contents.rst @@ -10,4 +10,4 @@ with human-friendly labels. .. toctree:: :maxdepth: 2 - /docs/type/namedval/namedval + /pyasn1/type/namedval/namedval diff --git a/doc/source/docs/type/namedval/namedval.rst b/docs/source/pyasn1/type/namedval/namedval.rst index 24847a9..24847a9 100644 --- a/doc/source/docs/type/namedval/namedval.rst +++ b/docs/source/pyasn1/type/namedval/namedval.rst diff --git a/doc/source/docs/type/opentype/contents.rst b/docs/source/pyasn1/type/opentype/contents.rst index 78f5a78..93b0a58 100644 --- a/doc/source/docs/type/opentype/contents.rst +++ b/docs/source/pyasn1/type/opentype/contents.rst @@ -5,4 +5,4 @@ Untyped fields of constructed types .. toctree:: :maxdepth: 2 - /docs/type/opentype/opentype + /pyasn1/type/opentype/opentype diff --git a/doc/source/docs/type/opentype/opentype.rst b/docs/source/pyasn1/type/opentype/opentype.rst index 2660bd9..f01ab5d 100644 --- a/doc/source/docs/type/opentype/opentype.rst +++ b/docs/source/pyasn1/type/opentype/opentype.rst @@ -11,4 +11,5 @@ The |OpenType| class models an untyped field of a constructed ASN.1 type. In ASN.1 syntax it is usually represented by the - `ANY DEFINED BY` clause. + `ANY DEFINED BY` clause. Typically used with `Any </pyasn1/type/univ/any>`_ + type. diff --git a/docs/source/pyasn1/type/tag/contents.rst b/docs/source/pyasn1/type/tag/contents.rst new file mode 100644 index 0000000..1d868b6 --- /dev/null +++ b/docs/source/pyasn1/type/tag/contents.rst @@ -0,0 +1,10 @@ + +Tagging types +------------- + +.. toctree:: + :maxdepth: 2 + + /pyasn1/type/tag/tag + /pyasn1/type/tag/tagset + /pyasn1/type/tag/tagmap diff --git a/doc/source/docs/type/tag/tag.rst b/docs/source/pyasn1/type/tag/tag.rst index 65be836..65be836 100644 --- a/doc/source/docs/type/tag/tag.rst +++ b/docs/source/pyasn1/type/tag/tag.rst diff --git a/doc/source/docs/type/tag/tagmap.rst b/docs/source/pyasn1/type/tag/tagmap.rst index 5891abc..5891abc 100644 --- a/doc/source/docs/type/tag/tagmap.rst +++ b/docs/source/pyasn1/type/tag/tagmap.rst diff --git a/doc/source/docs/type/tag/tagset.rst b/docs/source/pyasn1/type/tag/tagset.rst index 5ffb2fc..5ffb2fc 100644 --- a/doc/source/docs/type/tag/tagset.rst +++ b/docs/source/pyasn1/type/tag/tagset.rst diff --git a/doc/source/docs/type/univ/any.rst b/docs/source/pyasn1/type/univ/any.rst index d1aef27..089a792 100644 --- a/doc/source/docs/type/univ/any.rst +++ b/docs/source/pyasn1/type/univ/any.rst @@ -11,10 +11,10 @@ .. note:: - The |ASN.1| type models an arbitrary value of an arbitrary type. Sometimes - type is defined by accompanying object identifier or an integer identifier. - Frequently ANY value holds a serialized representation of some other ASN.1 - object. + The |ASN.1| type models an arbitrary value of an arbitrary type. Typically, + a selection of types are defined in form of an + `open type </pyasn1/type/opentype/contents>`_ . Technically, the ANY + value is a serialized 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') diff --git a/doc/source/docs/type/univ/bitstring.rst b/docs/source/pyasn1/type/univ/bitstring.rst index 17f6116..17f6116 100644 --- a/doc/source/docs/type/univ/bitstring.rst +++ b/docs/source/pyasn1/type/univ/bitstring.rst diff --git a/doc/source/docs/type/univ/boolean.rst b/docs/source/pyasn1/type/univ/boolean.rst index c486bd0..c486bd0 100644 --- a/doc/source/docs/type/univ/boolean.rst +++ b/docs/source/pyasn1/type/univ/boolean.rst diff --git a/doc/source/docs/type/univ/choice.rst b/docs/source/pyasn1/type/univ/choice.rst index 1507e9d..1507e9d 100644 --- a/doc/source/docs/type/univ/choice.rst +++ b/docs/source/pyasn1/type/univ/choice.rst diff --git a/docs/source/pyasn1/type/univ/contents.rst b/docs/source/pyasn1/type/univ/contents.rst new file mode 100644 index 0000000..af4a8f3 --- /dev/null +++ b/docs/source/pyasn1/type/univ/contents.rst @@ -0,0 +1,23 @@ + +Universal types +--------------- + +.. autoclass:: pyasn1.type.univ.NoValue() + +.. 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 diff --git a/doc/source/docs/type/univ/enumerated.rst b/docs/source/pyasn1/type/univ/enumerated.rst index 2e88e99..2e88e99 100644 --- a/doc/source/docs/type/univ/enumerated.rst +++ b/docs/source/pyasn1/type/univ/enumerated.rst diff --git a/doc/source/docs/type/univ/integer.rst b/docs/source/pyasn1/type/univ/integer.rst index fd9fbec..fd9fbec 100644 --- a/doc/source/docs/type/univ/integer.rst +++ b/docs/source/pyasn1/type/univ/integer.rst diff --git a/doc/source/docs/type/univ/null.rst b/docs/source/pyasn1/type/univ/null.rst index a959146..a959146 100644 --- a/doc/source/docs/type/univ/null.rst +++ b/docs/source/pyasn1/type/univ/null.rst diff --git a/doc/source/docs/type/univ/objectidentifier.rst b/docs/source/pyasn1/type/univ/objectidentifier.rst index c63140f..c63140f 100644 --- a/doc/source/docs/type/univ/objectidentifier.rst +++ b/docs/source/pyasn1/type/univ/objectidentifier.rst diff --git a/doc/source/docs/type/univ/octetstring.rst b/docs/source/pyasn1/type/univ/octetstring.rst index a58476d..a58476d 100644 --- a/doc/source/docs/type/univ/octetstring.rst +++ b/docs/source/pyasn1/type/univ/octetstring.rst diff --git a/doc/source/docs/type/univ/real.rst b/docs/source/pyasn1/type/univ/real.rst index f80c725..f80c725 100644 --- a/doc/source/docs/type/univ/real.rst +++ b/docs/source/pyasn1/type/univ/real.rst diff --git a/doc/source/docs/type/univ/sequence.rst b/docs/source/pyasn1/type/univ/sequence.rst index d9123d8..d9123d8 100644 --- a/doc/source/docs/type/univ/sequence.rst +++ b/docs/source/pyasn1/type/univ/sequence.rst diff --git a/doc/source/docs/type/univ/sequenceof.rst b/docs/source/pyasn1/type/univ/sequenceof.rst index 8f5c6f3..8f5c6f3 100644 --- a/doc/source/docs/type/univ/sequenceof.rst +++ b/docs/source/pyasn1/type/univ/sequenceof.rst diff --git a/doc/source/docs/type/univ/set.rst b/docs/source/pyasn1/type/univ/set.rst index 6216210..6216210 100644 --- a/doc/source/docs/type/univ/set.rst +++ b/docs/source/pyasn1/type/univ/set.rst diff --git a/doc/source/docs/type/univ/setof.rst b/docs/source/pyasn1/type/univ/setof.rst index 74fdd42..74fdd42 100644 --- a/doc/source/docs/type/univ/setof.rst +++ b/docs/source/pyasn1/type/univ/setof.rst diff --git a/docs/source/pyasn1/type/useful/contents.rst b/docs/source/pyasn1/type/useful/contents.rst new file mode 100644 index 0000000..2107349 --- /dev/null +++ b/docs/source/pyasn1/type/useful/contents.rst @@ -0,0 +1,10 @@ + +Useful types +------------ + +.. toctree:: + :maxdepth: 2 + + /pyasn1/type/useful/objectdescriptor + /pyasn1/type/useful/generalizedtime + /pyasn1/type/useful/utctime diff --git a/doc/source/docs/type/useful/generalizedtime.rst b/docs/source/pyasn1/type/useful/generalizedtime.rst index abf4351..abf4351 100644 --- a/doc/source/docs/type/useful/generalizedtime.rst +++ b/docs/source/pyasn1/type/useful/generalizedtime.rst diff --git a/doc/source/docs/type/useful/objectdescriptor.rst b/docs/source/pyasn1/type/useful/objectdescriptor.rst index 3b62a5d..3b62a5d 100644 --- a/doc/source/docs/type/useful/objectdescriptor.rst +++ b/docs/source/pyasn1/type/useful/objectdescriptor.rst diff --git a/doc/source/docs/type/useful/utctime.rst b/docs/source/pyasn1/type/useful/utctime.rst index 2ad86a9..2ad86a9 100644 --- a/doc/source/docs/type/useful/utctime.rst +++ b/docs/source/pyasn1/type/useful/utctime.rst diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py index af14753..7dc14ac 100644 --- a/pyasn1/codec/cer/encoder.py +++ b/pyasn1/codec/cer/encoder.py @@ -260,12 +260,6 @@ class Encoder(encoder.Encoder): #: asn1Spec: #: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: -#: defMode: :py:class:`bool` -#: If `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` (Python 3) or :py:class:`str` (Python 2) diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py index ac0bfb5..e410531 100644 --- a/pyasn1/codec/der/encoder.py +++ b/pyasn1/codec/der/encoder.py @@ -72,12 +72,6 @@ class Encoder(encoder.Encoder): #: asn1Spec: #: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: -#: defMode: :py:class:`bool` -#: If `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` (Python 3) or :py:class:`str` (Python 2) diff --git a/pyasn1/type/base.py b/pyasn1/type/base.py index 1b54d8d..4dd6a21 100644 --- a/pyasn1/type/base.py +++ b/pyasn1/type/base.py @@ -75,7 +75,7 @@ class Asn1ItemBase(Asn1Item): (:py:mod:`~pyasn1.type.constraint`) are examined when carrying out ASN.1 types comparison. - No Python inheritance relationship between PyASN1 objects is considered. + Python class inheritance relationship is NOT considered. Parameters ---------- @@ -99,8 +99,7 @@ class Asn1ItemBase(Asn1Item): (:py:mod:`~pyasn1.type.constraint`) are examined when carrying out ASN.1 types comparison. - No Python inheritance relationship between PyASN1 objects is considered. - + Python class inheritance relationship is NOT considered. Parameters ---------- @@ -145,11 +144,16 @@ class Asn1ItemBase(Asn1Item): class NoValue(object): """Create a singleton instance of NoValue class. - NoValue object can be used as an initializer on PyASN1 type class - instantiation to represent ASN.1 type rather than ASN.1 data value. + The *NoValue* sentinel object represents an instance of ASN.1 schema + object as opposed to ASN.1 value object. - No operations other than type comparison can be performed on - a PyASN1 type object. + Only ASN.1 schema-related operations can be performed on ASN.1 + schema objects. + + Warning + ------- + Any operation attempted on the *noValue* object will raise the + *PyAsn1Error* exception. """ skipMethods = ('__getattribute__', '__getattr__', '__setattr__', '__delattr__', '__class__', '__init__', '__del__', '__new__', '__repr__', @@ -161,7 +165,7 @@ class NoValue(object): if cls._instance is None: def getPlug(name): def plug(self, *args, **kw): - raise error.PyAsn1Error('Uninitialized ASN.1 value ("%s" attribute looked up)' % name) + raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name) return plug op_names = [name @@ -253,31 +257,35 @@ class AbstractSimpleAsn1Item(Asn1ItemBase): @property def isValue(self): - """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value. + """Indicate that |ASN.1| object represents ASN.1 value. - In other words, if *isValue* is `True`, then the ASN.1 object is - initialized. + If *isValue* is `False` then this object represents just ASN.1 schema. + + If *isValue* is `True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. `int`, + `str`, `dict` etc.). Returns ------- : :class:`bool` - :class:`True` if object represents ASN.1 value and type, - :class:`False` if object represents just ASN.1 type. + :class:`False` if object represents just ASN.1 schema. + :class:`True` if object represents ASN.1 schema and can be used as a normal value. Note ---- - There is an important distinction between PyASN1 type and value objects. - The PyASN1 type objects can only participate in ASN.1 type - operations (subtyping, comparison etc) and serve as a - blueprint for serialization codecs to resolve ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialization codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). """ return self._value is not noValue def clone(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -311,7 +319,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase): return self.__class__(value, **initilaizers) def subtype(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. @@ -369,7 +377,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase): return str(value) def prettyPrint(self, scope=0): - """Provide human-friendly printable object representation. + """Return human-friendly object representation as a text. Returns ------- @@ -408,6 +416,8 @@ class AbstractSimpleAsn1Item(Asn1ItemBase): # of types for Sequence/Set/Choice. # +# TODO: remove + def setupComponent(): """Returns a sentinel value. @@ -490,7 +500,7 @@ class AbstractConstructedAsn1Item(Asn1ItemBase): pass def clone(self, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -525,7 +535,7 @@ class AbstractConstructedAsn1Item(Asn1ItemBase): return clone def subtype(self, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. diff --git a/pyasn1/type/char.py b/pyasn1/type/char.py index 60f9d97..d430bd8 100644 --- a/pyasn1/type/char.py +++ b/pyasn1/type/char.py @@ -18,7 +18,7 @@ noValue = univ.noValue class AbstractCharacterString(univ.OctetString): - """Creates |ASN.1| type or object. + """Creates |ASN.1| schema or value object. |ASN.1| objects are immutable and duck-type Python 2 :class:`unicode` or Python 3 :class:`str`. When used in octet-stream context, |ASN.1| type assumes "|encoding|" encoding. @@ -126,7 +126,7 @@ class AbstractCharacterString(univ.OctetString): return reversed(self._value) def clone(self, value=noValue, **kwargs): - """Creates a copy of a |ASN.1| type or object. + """Creates a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -158,7 +158,7 @@ class AbstractCharacterString(univ.OctetString): return univ.OctetString.clone(self, value, **kwargs) def subtype(self, value=noValue, **kwargs): - """Creates a copy of a |ASN.1| type or object. + """Creates a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py index a0d0e01..8e78f77 100644 --- a/pyasn1/type/univ.py +++ b/pyasn1/type/univ.py @@ -245,7 +245,7 @@ class Integer(base.AbstractSimpleAsn1Item): return str(value) def clone(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -273,7 +273,7 @@ class Integer(base.AbstractSimpleAsn1Item): return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) def subtype(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. @@ -340,7 +340,7 @@ class Boolean(Integer): class BitString(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. + """Create |ASN.1| schema or value object. |ASN.1| objects are immutable and duck-type both Python :class:`tuple` (as a tuple of bits) and :class:`int` objects. @@ -441,7 +441,7 @@ class BitString(base.AbstractSimpleAsn1Item): base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs) def clone(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -477,7 +477,7 @@ class BitString(base.AbstractSimpleAsn1Item): return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) def subtype(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. @@ -783,7 +783,7 @@ except NameError: # Python 2.4 class OctetString(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. + """Create |ASN.1| schema or value object. |ASN.1| objects are immutable and duck-type Python 2 :class:`str` or Python 3 :class:`bytes`. When used in Unicode context, |ASN.1| type assumes "|encoding|" serialization. @@ -865,7 +865,7 @@ class OctetString(base.AbstractSimpleAsn1Item): base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs) def clone(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -901,7 +901,7 @@ class OctetString(base.AbstractSimpleAsn1Item): return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) def subtype(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. @@ -1151,7 +1151,7 @@ class OctetString(base.AbstractSimpleAsn1Item): class Null(OctetString): - """Create |ASN.1| type or object. + """Create |ASN.1| schema or value object. |ASN.1| objects are immutable and duck-type Python :class:`str` objects (always empty). @@ -1182,7 +1182,7 @@ class Null(OctetString): typeId = OctetString.getTypeId() def clone(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -1204,7 +1204,7 @@ class Null(OctetString): return OctetString.clone(self, value, **kwargs) def subtype(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. @@ -1242,7 +1242,7 @@ numericTypes = intTypes + (float,) class ObjectIdentifier(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. + """Create |ASN.1| schema or value object. |ASN.1| objects are immutable and duck-type Python :class:`tuple` objects (tuple of non-negative integers). @@ -1365,7 +1365,7 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item): class Real(base.AbstractSimpleAsn1Item): - """Create |ASN.1| type or object. + """Create |ASN.1| schema or value object. |ASN.1| objects are immutable and duck-type Python :class:`float` objects. Additionally, |ASN.1| objects behave like a :class:`tuple` in which case its @@ -1416,7 +1416,7 @@ class Real(base.AbstractSimpleAsn1Item): typeId = base.AbstractSimpleAsn1Item.getTypeId() def clone(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *clone()* method will replace corresponding properties of the |ASN.1| object. @@ -1441,7 +1441,7 @@ class Real(base.AbstractSimpleAsn1Item): return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) def subtype(self, value=noValue, **kwargs): - """Create a copy of a |ASN.1| type or object. + """Create a copy of a |ASN.1| schema or value object. Any parameters to the *subtype()* method will be added to the corresponding properties of the |ASN.1| object. @@ -1955,29 +1955,30 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item): @property def isValue(self): - """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value. - - In other words, if *isValue* is `True`, then the ASN.1 object is - initialized. + """Indicate that |ASN.1| object represents ASN.1 value. - For the purpose of this check, empty |ASN.1| object is considered - as initialized. + If *isValue* is `False` then this object represents just ASN.1 schema. + + If *isValue* is `True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. `int`, + `str`, `dict` etc.). Returns ------- : :class:`bool` - :class:`True` if object represents ASN.1 value and type, - :class:`False` if object represents just ASN.1 type. + :class:`False` if object represents just ASN.1 schema. + :class:`True` if object represents ASN.1 schema and can be used as a normal value. Note ---- - There is an important distinction between PyASN1 type and value objects. - The PyASN1 type objects can only participate in ASN.1 type - operations (subtyping, comparison etc) and serve as a - blueprint for serialization codecs to resolve ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialization codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). """ for componentValue in self._componentValues: if not componentValue.isValue: @@ -2267,7 +2268,7 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item): ---------- idx : :class:`int` Component index (zero-based). Must either refer to an existing - component or (if *componentType* is set) new ASN.1 type object gets + component or (if *componentType* is set) new ASN.1 schema object gets instantiated. Returns @@ -2379,29 +2380,30 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item): @property def isValue(self): - """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value. + """Indicate that |ASN.1| object represents ASN.1 value. - In other words, if *isValue* is `True`, then the ASN.1 object is - initialized. - - For the purpose of check, the *OPTIONAL* and *DEFAULT* fields are - unconditionally considered as initialized. + If *isValue* is `False` then this object represents just ASN.1 schema. + + If *isValue* is `True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. `int`, + `str`, `dict` etc.). Returns ------- : :class:`bool` - :class:`True` if object represents ASN.1 value and type, - :class:`False` if object represents just ASN.1 type. + :class:`False` if object represents just ASN.1 schema. + :class:`True` if object represents ASN.1 schema and can be used as a normal value. Note ---- - There is an important distinction between PyASN1 type and value objects. - The PyASN1 type objects can only participate in ASN.1 type - operations (subtyping, comparison etc) and serve as a - blueprint for serialization codecs to resolve ambiguous types. - - The PyASN1 value objects can additionally participate in most - of built-in Python operations. + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialization codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). """ componentType = self.componentType @@ -2837,20 +2839,30 @@ class Choice(Set): @property def isValue(self): - """Indicate if |ASN.1| component is set and represents ASN.1 type or ASN.1 value. - - The PyASN1 type objects can only participate in types comparison - and serve as a blueprint for serialization codecs to resolve - ambiguous types. + """Indicate that |ASN.1| object represents ASN.1 value. - The PyASN1 value objects can additionally participate in most - of built-in Python operations. + If *isValue* is `False` then this object represents just ASN.1 schema. + + If *isValue* is `True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. `int`, + `str`, `dict` etc.). Returns ------- : :class:`bool` - :class:`True` if |ASN.1| component is set and represent value and type, - :class:`False` if |ASN.1| component is not set or it represents just ASN.1 type. + :class:`False` if object represents just ASN.1 schema. + :class:`True` if object represents ASN.1 schema and can be used as a normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialization codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). """ if self._currentIdx is None: return False |