From e577789849a0aaf302504a5914fecd80203a4378 Mon Sep 17 00:00:00 2001 From: David Keeler Date: Fri, 3 Nov 2017 16:53:21 -0700 Subject: [PATCH] bug 1413336 - (1/7) update pyasn1 to 0.3.7 r=ted MozReview-Commit-ID: L3bvhOZRQyN --HG-- rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/pyasn1/codec/native/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/codec/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/codec/ber/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/codec/cer/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/codec/der/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/codec/native/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/compat/__init__.py rename : third_party/python/pyasn1/test/__init__.py => third_party/python/pyasn1/tests/type/__init__.py extra : rebase_source : e44063fcc7984b4c64906cf095390c2210404684 --- third_party/python/pyasn1/CHANGES | 278 -- third_party/python/pyasn1/CHANGES.rst | 576 +++ .../python/pyasn1/{LICENSE => LICENSE.rst} | 2 +- third_party/python/pyasn1/MANIFEST.in | 8 +- third_party/python/pyasn1/PKG-INFO | 23 +- third_party/python/pyasn1/README | 68 - third_party/python/pyasn1/README.md | 184 + third_party/python/pyasn1/THANKS | 4 - third_party/python/pyasn1/TODO | 36 - third_party/python/pyasn1/TODO.rst | 92 + third_party/python/pyasn1/doc/Makefile | 192 + third_party/python/pyasn1/doc/codecs.html | 503 --- .../python/pyasn1/doc/constraints.html | 436 --- .../python/pyasn1/doc/constructed.html | 377 -- third_party/python/pyasn1/doc/intro.html | 156 - .../python/pyasn1/doc/pyasn1-tutorial.html | 2405 ------------ third_party/python/pyasn1/doc/scalar.html | 794 ---- .../python/pyasn1/doc/source/changelog.rst | 6 + third_party/python/pyasn1/doc/source/conf.py | 323 ++ .../python/pyasn1/doc/source/contents.rst | 194 + .../pyasn1/doc/source/docs/api-reference.rst | 30 + .../doc/source/docs/codec/ber/contents.rst | 7 + .../doc/source/docs/codec/cer/contents.rst | 7 + .../doc/source/docs/codec/der/contents.rst | 7 + .../doc/source/docs/codec/native/contents.rst | 7 + .../pyasn1/doc/source/docs/tutorial.rst | 1778 +++++++++ .../doc/source/docs/type/char/bmpstring.rst | 17 + .../doc/source/docs/type/char/contents.rst | 20 + .../source/docs/type/char/generalstring.rst | 18 + .../source/docs/type/char/graphicstring.rst | 18 + .../doc/source/docs/type/char/ia5string.rst | 17 + .../source/docs/type/char/iso646string.rst | 17 + .../source/docs/type/char/numericstring.rst | 17 + .../source/docs/type/char/printablestring.rst | 18 + .../doc/source/docs/type/char/t61string.rst | 17 + .../source/docs/type/char/teletexstring.rst | 19 + .../source/docs/type/char/universalstring.rst | 17 + .../doc/source/docs/type/char/utf8string.rst | 17 + .../source/docs/type/char/videotexstring.rst | 18 + .../source/docs/type/char/visiblestring.rst | 18 + .../source/docs/type/namedtype/contents.rst | 11 + .../type/namedtype/defaultednamedtype.rst | 12 + .../source/docs/type/namedtype/namedtype.rst | 12 + .../source/docs/type/namedtype/namedtypes.rst | 6 + .../docs/type/namedtype/optionalnamedtype.rst | 12 + .../source/docs/type/namedval/contents.rst | 13 + .../source/docs/type/namedval/namedval.rst | 11 + .../doc/source/docs/type/tag/contents.rst | 10 + .../pyasn1/doc/source/docs/type/tag/tag.rst | 8 + .../doc/source/docs/type/tag/tagmap.rst | 6 + .../doc/source/docs/type/tag/tagset.rst | 6 + .../pyasn1/doc/source/docs/type/univ/any.rst | 20 + .../doc/source/docs/type/univ/bitstring.rst | 15 + .../doc/source/docs/type/univ/boolean.rst | 15 + .../doc/source/docs/type/univ/choice.rst | 17 + .../doc/source/docs/type/univ/contents.rst | 23 + .../doc/source/docs/type/univ/enumerated.rst | 16 + .../doc/source/docs/type/univ/integer.rst | 17 + .../pyasn1/doc/source/docs/type/univ/null.rst | 15 + .../docs/type/univ/objectidentifier.rst | 15 + .../doc/source/docs/type/univ/octetstring.rst | 17 + .../pyasn1/doc/source/docs/type/univ/real.rst | 15 + .../doc/source/docs/type/univ/sequence.rst | 17 + .../doc/source/docs/type/univ/sequenceof.rst | 17 + .../pyasn1/doc/source/docs/type/univ/set.rst | 18 + .../doc/source/docs/type/univ/setof.rst | 17 + .../doc/source/docs/type/useful/contents.rst | 10 + .../docs/type/useful/generalizedtime.rst | 35 + .../docs/type/useful/objectdescriptor.rst | 18 + .../doc/source/docs/type/useful/utctime.rst | 32 + .../pyasn1/doc/source/example-use-case.rst | 193 + .../python/pyasn1/doc/source/license.rst | 6 + third_party/python/pyasn1/doc/tagging.html | 233 -- .../python/pyasn1/pyasn1.egg-info/PKG-INFO | 23 +- .../python/pyasn1/pyasn1.egg-info/SOURCES.txt | 139 +- third_party/python/pyasn1/pyasn1/__init__.py | 5 +- .../python/pyasn1/pyasn1/codec/ber/decoder.py | 1386 ++++--- .../python/pyasn1/pyasn1/codec/ber/encoder.py | 635 ++-- .../python/pyasn1/pyasn1/codec/ber/eoo.py | 19 +- .../python/pyasn1/pyasn1/codec/cer/decoder.py | 77 +- .../python/pyasn1/pyasn1/codec/cer/encoder.py | 252 +- .../python/pyasn1/pyasn1/codec/der/decoder.py | 69 +- .../python/pyasn1/pyasn1/codec/der/encoder.py | 66 +- .../{test => pyasn1/codec/native}/__init__.py | 0 .../pyasn1/pyasn1/codec/native/decoder.py | 194 + .../pyasn1/pyasn1/codec/native/encoder.py | 212 ++ .../python/pyasn1/pyasn1/compat/binary.py | 33 + .../python/pyasn1/pyasn1/compat/calling.py | 20 + .../pyasn1/pyasn1/compat/dateandtime.py | 22 + .../python/pyasn1/pyasn1/compat/integer.py | 108 + .../python/pyasn1/pyasn1/compat/octets.py | 36 +- .../python/pyasn1/pyasn1/compat/string.py | 26 + third_party/python/pyasn1/pyasn1/debug.py | 128 +- third_party/python/pyasn1/pyasn1/error.py | 21 +- third_party/python/pyasn1/pyasn1/type/base.py | 684 +++- third_party/python/pyasn1/pyasn1/type/char.py | 387 +- .../python/pyasn1/pyasn1/type/constraint.py | 174 +- .../python/pyasn1/pyasn1/type/error.py | 10 +- .../python/pyasn1/pyasn1/type/namedtype.py | 587 ++- .../python/pyasn1/pyasn1/type/namedval.py | 209 +- third_party/python/pyasn1/pyasn1/type/tag.py | 360 +- .../python/pyasn1/pyasn1/type/tagmap.py | 132 +- third_party/python/pyasn1/pyasn1/type/univ.py | 3299 +++++++++++++---- .../python/pyasn1/pyasn1/type/useful.py | 187 +- third_party/python/pyasn1/setup.cfg | 3 + third_party/python/pyasn1/setup.py | 125 +- .../python/pyasn1/test/codec/ber/suite.py | 22 - .../pyasn1/test/codec/ber/test_decoder.py | 535 --- .../pyasn1/test/codec/ber/test_encoder.py | 338 -- .../python/pyasn1/test/codec/cer/suite.py | 22 - .../pyasn1/test/codec/cer/test_decoder.py | 31 - .../pyasn1/test/codec/cer/test_encoder.py | 107 - .../python/pyasn1/test/codec/der/suite.py | 22 - .../pyasn1/test/codec/der/test_decoder.py | 20 - .../pyasn1/test/codec/der/test_encoder.py | 44 - third_party/python/pyasn1/test/codec/suite.py | 29 - third_party/python/pyasn1/test/suite.py | 26 - third_party/python/pyasn1/test/type/suite.py | 20 - .../python/pyasn1/test/type/test_namedtype.py | 87 - .../python/pyasn1/test/type/test_univ.py | 479 --- .../pyasn1/{test/codec => tests}/__init__.py | 0 third_party/python/pyasn1/tests/__main__.py | 22 + third_party/python/pyasn1/tests/base.py | 22 + .../codec/ber => tests/codec}/__init__.py | 0 .../python/pyasn1/tests/codec/__main__.py | 22 + .../codec/cer => tests/codec/ber}/__init__.py | 0 .../python/pyasn1/tests/codec/ber/__main__.py | 20 + .../pyasn1/tests/codec/ber/test_decoder.py | 1294 +++++++ .../pyasn1/tests/codec/ber/test_encoder.py | 940 +++++ .../codec/der => tests/codec/cer}/__init__.py | 0 .../python/pyasn1/tests/codec/cer/__main__.py | 20 + .../pyasn1/tests/codec/cer/test_decoder.py | 71 + .../pyasn1/tests/codec/cer/test_encoder.py | 677 ++++ .../type => tests/codec/der}/__init__.py | 0 .../python/pyasn1/tests/codec/der/__main__.py | 20 + .../pyasn1/tests/codec/der/test_decoder.py | 78 + .../pyasn1/tests/codec/der/test_encoder.py | 295 ++ .../pyasn1/tests/codec/native/__init__.py | 1 + .../pyasn1/tests/codec/native/__main__.py | 19 + .../pyasn1/tests/codec/native/test_decoder.py | 123 + .../pyasn1/tests/codec/native/test_encoder.py | 144 + .../python/pyasn1/tests/compat/__init__.py | 1 + .../python/pyasn1/tests/compat/__main__.py | 21 + .../python/pyasn1/tests/compat/test_binary.py | 56 + .../pyasn1/tests/compat/test_integer.py | 53 + .../python/pyasn1/tests/compat/test_octets.py | 117 + third_party/python/pyasn1/tests/test_debug.py | 42 + .../python/pyasn1/tests/type/__init__.py | 1 + .../python/pyasn1/tests/type/__main__.py | 25 + .../python/pyasn1/tests/type/test_char.py | 156 + .../{test => tests}/type/test_constraint.py | 172 +- .../pyasn1/tests/type/test_namedtype.py | 147 + .../python/pyasn1/tests/type/test_namedval.py | 58 + .../pyasn1/{test => tests}/type/test_tag.py | 87 +- .../python/pyasn1/tests/type/test_univ.py | 1503 ++++++++ .../python/pyasn1/tests/type/test_useful.py | 104 + 156 files changed, 17978 insertions(+), 9372 deletions(-) delete mode 100644 third_party/python/pyasn1/CHANGES create mode 100644 third_party/python/pyasn1/CHANGES.rst rename third_party/python/pyasn1/{LICENSE => LICENSE.rst} (95%) delete mode 100644 third_party/python/pyasn1/README create mode 100644 third_party/python/pyasn1/README.md delete mode 100644 third_party/python/pyasn1/THANKS delete mode 100644 third_party/python/pyasn1/TODO create mode 100644 third_party/python/pyasn1/TODO.rst create mode 100644 third_party/python/pyasn1/doc/Makefile delete mode 100644 third_party/python/pyasn1/doc/codecs.html delete mode 100644 third_party/python/pyasn1/doc/constraints.html delete mode 100644 third_party/python/pyasn1/doc/constructed.html delete mode 100644 third_party/python/pyasn1/doc/intro.html delete mode 100644 third_party/python/pyasn1/doc/pyasn1-tutorial.html delete mode 100644 third_party/python/pyasn1/doc/scalar.html create mode 100644 third_party/python/pyasn1/doc/source/changelog.rst create mode 100644 third_party/python/pyasn1/doc/source/conf.py create mode 100644 third_party/python/pyasn1/doc/source/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/api-reference.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/codec/ber/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/codec/cer/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/codec/der/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/codec/native/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/tutorial.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/bmpstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/generalstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/graphicstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/ia5string.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/iso646string.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/numericstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/printablestring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/t61string.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/teletexstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/universalstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/utf8string.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/videotexstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/char/visiblestring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedtype/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedtype/defaultednamedtype.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtype.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtypes.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedtype/optionalnamedtype.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedval/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/namedval/namedval.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/tag/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/tag/tag.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/tag/tagmap.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/tag/tagset.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/any.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/bitstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/boolean.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/choice.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/enumerated.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/integer.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/null.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/objectidentifier.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/octetstring.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/real.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/sequence.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/sequenceof.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/set.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/univ/setof.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/useful/contents.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/useful/generalizedtime.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/useful/objectdescriptor.rst create mode 100644 third_party/python/pyasn1/doc/source/docs/type/useful/utctime.rst create mode 100644 third_party/python/pyasn1/doc/source/example-use-case.rst create mode 100644 third_party/python/pyasn1/doc/source/license.rst delete mode 100644 third_party/python/pyasn1/doc/tagging.html rename third_party/python/pyasn1/{test => pyasn1/codec/native}/__init__.py (100%) create mode 100644 third_party/python/pyasn1/pyasn1/codec/native/decoder.py create mode 100644 third_party/python/pyasn1/pyasn1/codec/native/encoder.py create mode 100644 third_party/python/pyasn1/pyasn1/compat/binary.py create mode 100644 third_party/python/pyasn1/pyasn1/compat/calling.py create mode 100644 third_party/python/pyasn1/pyasn1/compat/dateandtime.py create mode 100644 third_party/python/pyasn1/pyasn1/compat/integer.py create mode 100644 third_party/python/pyasn1/pyasn1/compat/string.py delete mode 100644 third_party/python/pyasn1/test/codec/ber/suite.py delete mode 100644 third_party/python/pyasn1/test/codec/ber/test_decoder.py delete mode 100644 third_party/python/pyasn1/test/codec/ber/test_encoder.py delete mode 100644 third_party/python/pyasn1/test/codec/cer/suite.py delete mode 100644 third_party/python/pyasn1/test/codec/cer/test_decoder.py delete mode 100644 third_party/python/pyasn1/test/codec/cer/test_encoder.py delete mode 100644 third_party/python/pyasn1/test/codec/der/suite.py delete mode 100644 third_party/python/pyasn1/test/codec/der/test_decoder.py delete mode 100644 third_party/python/pyasn1/test/codec/der/test_encoder.py delete mode 100644 third_party/python/pyasn1/test/codec/suite.py delete mode 100644 third_party/python/pyasn1/test/suite.py delete mode 100644 third_party/python/pyasn1/test/type/suite.py delete mode 100644 third_party/python/pyasn1/test/type/test_namedtype.py delete mode 100644 third_party/python/pyasn1/test/type/test_univ.py rename third_party/python/pyasn1/{test/codec => tests}/__init__.py (100%) create mode 100644 third_party/python/pyasn1/tests/__main__.py create mode 100644 third_party/python/pyasn1/tests/base.py rename third_party/python/pyasn1/{test/codec/ber => tests/codec}/__init__.py (100%) create mode 100644 third_party/python/pyasn1/tests/codec/__main__.py rename third_party/python/pyasn1/{test/codec/cer => tests/codec/ber}/__init__.py (100%) create mode 100644 third_party/python/pyasn1/tests/codec/ber/__main__.py create mode 100644 third_party/python/pyasn1/tests/codec/ber/test_decoder.py create mode 100644 third_party/python/pyasn1/tests/codec/ber/test_encoder.py rename third_party/python/pyasn1/{test/codec/der => tests/codec/cer}/__init__.py (100%) create mode 100644 third_party/python/pyasn1/tests/codec/cer/__main__.py create mode 100644 third_party/python/pyasn1/tests/codec/cer/test_decoder.py create mode 100644 third_party/python/pyasn1/tests/codec/cer/test_encoder.py rename third_party/python/pyasn1/{test/type => tests/codec/der}/__init__.py (100%) create mode 100644 third_party/python/pyasn1/tests/codec/der/__main__.py create mode 100644 third_party/python/pyasn1/tests/codec/der/test_decoder.py create mode 100644 third_party/python/pyasn1/tests/codec/der/test_encoder.py create mode 100644 third_party/python/pyasn1/tests/codec/native/__init__.py create mode 100644 third_party/python/pyasn1/tests/codec/native/__main__.py create mode 100644 third_party/python/pyasn1/tests/codec/native/test_decoder.py create mode 100644 third_party/python/pyasn1/tests/codec/native/test_encoder.py create mode 100644 third_party/python/pyasn1/tests/compat/__init__.py create mode 100644 third_party/python/pyasn1/tests/compat/__main__.py create mode 100644 third_party/python/pyasn1/tests/compat/test_binary.py create mode 100644 third_party/python/pyasn1/tests/compat/test_integer.py create mode 100644 third_party/python/pyasn1/tests/compat/test_octets.py create mode 100644 third_party/python/pyasn1/tests/test_debug.py create mode 100644 third_party/python/pyasn1/tests/type/__init__.py create mode 100644 third_party/python/pyasn1/tests/type/__main__.py create mode 100644 third_party/python/pyasn1/tests/type/test_char.py rename third_party/python/pyasn1/{test => tests}/type/test_constraint.py (71%) create mode 100644 third_party/python/pyasn1/tests/type/test_namedtype.py create mode 100644 third_party/python/pyasn1/tests/type/test_namedval.py rename third_party/python/pyasn1/{test => tests}/type/test_tag.py (69%) create mode 100644 third_party/python/pyasn1/tests/type/test_univ.py create mode 100644 third_party/python/pyasn1/tests/type/test_useful.py diff --git a/third_party/python/pyasn1/CHANGES b/third_party/python/pyasn1/CHANGES deleted file mode 100644 index 561dedd882af..000000000000 --- a/third_party/python/pyasn1/CHANGES +++ /dev/null @@ -1,278 +0,0 @@ -Revision 0.1.7 --------------- - -- License updated to vanilla BSD 2-Clause to ease package use - (http://opensource.org/licenses/BSD-2-Clause). -- Test suite made discoverable by unittest/unittest2 discovery feature. -- Fix to decoder working on indefinite length substrate -- end-of-octets - marker is now detected by both tag and value. Otherwise zero values may - interfere with end-of-octets marker. -- Fix to decoder to fail in cases where tagFormat indicates inappropriate - format for the type (e.g. BOOLEAN is always PRIMITIVE, SET is always - CONSTRUCTED and OCTET STRING is either of the two) -- Fix to REAL type encoder to force primitive encoding form encoding. -- Fix to CHOICE decoder to handle explicitly tagged, indefinite length - mode encoding -- Fix to REAL type decoder to handle negative REAL values correctly. Test - case added. - -Revision 0.1.6 --------------- - -- The compact (valueless) way of encoding zero INTEGERs introduced in - 0.1.5 seems to fail miserably as the world is filled with broken - BER decoders. So we had to back off the *encoder* for a while. - There's still the IntegerEncoder.supportCompactZero flag which - enables compact encoding form whenever it evaluates to True. -- Report package version on debugging code initialization. - -Revision 0.1.5 --------------- - -- Documentation updated and split into chapters to better match - web-site contents. -- Make prettyPrint() working for non-initialized pyasn1 data objects. It - used to throw an exception. -- Fix to encoder to produce empty-payload INTEGER values for zeros -- Fix to decoder to support empty-payload INTEGER and REAL values -- Fix to unit test suites imports to be able to run each from - their current directory - -Revision 0.1.4 --------------- - -- Built-in codec debugging facility added -- Added some more checks to ObjectIdentifier BER encoder catching - posible 2^8 overflow condition by two leading sub-OIDs -- Implementations overriding the AbstractDecoder.valueDecoder method - changed to return the rest of substrate behind the item being processed - rather than the unprocessed substrate within the item (which is usually - empty). -- Decoder's recursiveFlag feature generalized as a user callback function - which is passed an uninitialized object recovered from substrate and - its uninterpreted payload. -- Catch inappropriate substrate type passed to decoder. -- Expose tagMap/typeMap/Decoder objects at DER decoder to uniform API. -- Obsolete __init__.MajorVersionId replaced with __init__.__version__ - which is now in-sync with distutils. -- Package classifiers updated. -- The __init__.py's made non-empty (rumors are that they may be optimized - out by package managers). -- Bail out gracefully whenever Python version is older than 2.4. -- Fix to Real codec exponent encoding (should be in 2's complement form), - some more test cases added. -- Fix in Boolean truth testing built-in methods -- Fix to substrate underrun error handling at ObjectIdentifier BER decoder -- Fix to BER Boolean decoder that allows other pre-computed - values besides 0 and 1 -- Fix to leading 0x80 octet handling in DER/CER/DER ObjectIdentifier decoder. - See http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf - -Revision 0.1.3 --------------- - -- Include class name into asn1 value constraint violation exception. -- Fix to OctetString.prettyOut() method that looses leading zero when - building hex string. - -Revision 0.1.2 --------------- - -- Fix to __long__() to actually return longs on py2k -- Fix to OctetString.__str__() workings of a non-initialized object. -- Fix to quote initializer of OctetString.__repr__() -- Minor fix towards ObjectIdentifier.prettyIn() reliability -- ObjectIdentifier.__str__() is aliased to prettyPrint() -- Exlicit repr() calls replaced with '%r' - -Revision 0.1.1 --------------- - -- Hex/bin string initializer to OctetString object reworked - (in a backward-incompatible manner) -- Fixed float() infinity compatibility issue (affects 2.5 and earlier) -- Fixed a bug/typo at Boolean CER encoder. -- Major overhawl for Python 2.4 -- 3.2 compatibility: - + get rid of old-style types - + drop string module usage - + switch to rich comparation - + drop explicit long integer type use - + map()/filter() replaced with list comprehension - + apply() replaced with */**args - + switched to use 'key' sort() callback function - + support both __nonzero__() and __bool__() methods - + modified not to use py3k-incompatible exception syntax - + getslice() operator fully replaced with getitem() - + dictionary operations made 2K/3K compatible - + base type for encoding substrate and OctetString-based types - is now 'bytes' when running py3k and 'str' otherwise - + OctetString and derivatives now unicode compliant. - + OctetString now supports two python-neutral getters: asOcts() & asInts() - + print OctetString content in hex whenever it is not printable otherwise - + in test suite, implicit relative import replaced with the absolute one - + in test suite, string constants replaced with numerics - -Revision 0.0.13 ---------------- - -- Fix to base10 normalization function that loops on univ.Real(0) - -Revision 0.0.13b ----------------- - -- ASN.1 Real type is now supported properly. -- Objects of Constructed types now support __setitem__() -- Set/Sequence objects can now be addressed by their field names (string index) - and position (integer index). -- Typo fix to ber.SetDecoder code that prevented guided decoding operation. -- Fix to explicitly tagged items decoding support. -- Fix to OctetString.prettyPrint() to better handle non-printable content. -- Fix to repr() workings of Choice objects. - -Revision 0.0.13a ----------------- - -- Major codec re-design. -- Documentation significantly improved. -- ASN.1 Any type is now supported. -- All example ASN.1 modules moved to separate pyasn1-modules package. -- Fix to initial sub-OID overflow condition detection an encoder. -- BitString initialization value verification improved. -- The Set/Sequence.getNameByPosition() method implemented. -- Fix to proper behaviour of PermittedAlphabetConstraint object. -- Fix to improper Boolean substrate handling at CER/DER decoders. -- Changes towards performance improvement: - + all dict.has_key() & dict.get() invocations replaced with modern syntax - (this breaks compatibility with Python 2.1 and older). - + tag and tagset caches introduced to decoder - + decoder code improved to prevent unnecessary pyasn1 objects creation - + allow disabling components verification when setting components to - structured types, this is used by decoder whilst running in guided mode. - + BER decoder for integer values now looks up a small set of pre-computed - substrate values to save on decoding. - + a few pre-computed values configured to ObjectIdentifier BER encoder. - + ChoiceDecoder split-off SequenceOf one to save on unnecessary checks. - + replace slow hasattr()/getattr() calls with isinstance() introspection. - + track the number of initialized components of Constructed types to save - on default/optional components initialization. - + added a shortcut ObjectIdentifier.asTuple() to be used instead of - __getitem__() in hotspots. - + use Tag.asTuple() and pure integers at tag encoder. - + introduce and use in decoder the baseTagSet attribute of the built-in - ASN.1 types. - -Revision 0.0.12a ----------------- - -- The individual tag/length/value processing methods of - encoder.AbstractItemEncoder renamed (leading underscore stripped) - to promote overloading in cases where partial substrate processing - is required. -- The ocsp.py, ldap.py example scripts added. -- Fix to univ.ObjectIdentifier input value handler to disallow negative - sub-IDs. - -Revision 0.0.11a ----------------- - -- Decoder can now treat values of unknown types as opaque OctetString. -- Fix to Set/SetOf type decoder to handle uninitialized scalar SetOf - components correctly. - -Revision 0.0.10a ----------------- - -- API versioning mechanics retired (pyasn1.v1 -> pyasn1) what makes - it possible to zip-import pyasn1 sources (used by egg and py2exe). - -Revision 0.0.9a ---------------- - -- Allow any non-zero values in Boolean type BER decoder, as it's in - accordnance with the standard. - -Revision 0.0.8a ---------------- - -- Integer.__index__() now supported (for Python 2.5+). -- Fix to empty value encoding in BitString encoder, test case added. -- Fix to SequenceOf decoder that prevents it skipping possible Choice - typed inner component. -- Choice.getName() method added for getting currently set component - name. -- OctetsString.prettyPrint() does a single str() against its value - eliminating an extra quotes. - -Revision 0.0.7a ---------------- - -- Large tags (>31) now supported by codecs. -- Fix to encoder to properly handle explicitly tagged untagged items. -- All possible value lengths (up to 256^126) now supported by encoders. -- Fix to Tag class constructor to prevent negative IDs. - -Revision 0.0.6a ---------------- - -- Make use of setuptools. -- Constraints derivation verification (isSuperTypeOf()/isSubTypeOf()) fixed. -- Fix to constraints comparation logic -- can't cmp() hash values as it - may cause false positives due to hash conflicts. - -Revision 0.0.5a ---------------- - -- Integer BER codec reworked fixing negative values encoding bug. -- clone() and subtype() methods of Constructed ASN.1 classes now - accept optional cloneValueFlag flag which controls original value - inheritance. The default is *not* to inherit original value for - performance reasons (this may affect backward compatibility). - Performance penalty may be huge on deeply nested Constructed objects - re-creation. -- Base ASN.1 types (pyasn1.type.univ.*) do not have default values - anymore. They remain uninitialized acting as ASN.1 types. In - this model, initialized ASN.1 types represent either types with - default value installed or a type instance. -- Decoders' prototypes are now class instances rather than classes. - This is to simplify initial value installation to decoder's - prototype value. -- Bugfix to BitString BER decoder (trailing bits not regarded). -- Bugfix to Constraints use as mapping keys. -- Bugfix to Integer & BitString clone() methods -- Bugix to the way to distinguish Set from SetOf at CER/DER SetOfEncoder -- Adjustments to make it running on Python 1.5. -- In tests, substrate constants converted from hex escaped literals into - octals to overcome indefinite hex width issue occuring in young Python. -- Minor performance optimization of TagSet.isSuperTagSetOf() method -- examples/sshkey.py added - -Revision 0.0.4a ---------------- - -* Asn1ItemBase.prettyPrinter() -> *.prettyPrint() - -Revision 0.0.3a ---------------- - -* Simple ASN1 objects now hash to their Python value and don't - depend upon tag/constraints/etc. -* prettyIn & prettyOut methods of SimplleAsn1Object become public -* many syntax fixes - -Revision 0.0.2a ---------------- - -* ConstraintsIntersection.isSuperTypeOf() and - ConstraintsIntersection.hasConstraint() implemented -* Bugfix to NamedValues initialization code -* +/- operators added to NamedValues objects -* Integer.__abs__() & Integer.subtype() added -* ObjectIdentifier.prettyOut() fixes -* Allow subclass components at SequenceAndSetBase -* AbstractConstraint.__cmp__() dropped -* error.Asn1Error replaced with error.PyAsn1Error - -Revision 0.0.1a ---------------- - -* Initial public alpha release diff --git a/third_party/python/pyasn1/CHANGES.rst b/third_party/python/pyasn1/CHANGES.rst new file mode 100644 index 000000000000..d07cb35a085e --- /dev/null +++ b/third_party/python/pyasn1/CHANGES.rst @@ -0,0 +1,576 @@ + +Revision 0.3.7, released 04-10-2017 +----------------------------------- + +- Fixed ASN.1 time types pickling/deepcopy'ing + +Revision 0.3.6, released 21-09-2017 +----------------------------------- + +- End-of-octets encoding optimized at ASN.1 encoders +- The __getitem__/__setitem__ behavior of Set/Sequence and SetOf/SequenceOf + objects aligned with the canonical Mapping and Sequence protocols in part +- Fixed crash in ASN.1 encoder when encoding an explicitly tagged + component of a Sequence + +Revision 0.3.5, released 16-09-2017 +----------------------------------- + +- Codecs signatures unified and pass the options kwargs through the + call chain +- Explicit tag encoding optimized to avoid unnecessary copying +- End-of-octets sentinel encoding optimized +- Refactored ASN.1 codecs properties to silently enforce proper + length and chunk size encoding modes +- Fixed DER encoder to always produce primitive encoding +- Fixed crash at SequenceOf native decoder +- Fixed Real.prettyPrint() to fail gracefully on overflow +- Fixed a couple of crashes when debug mode is enabled + +Revision 0.3.4, released 07-09-2017 +----------------------------------- + +- Fixed Native encoder to handle SEQUENCE/SET objects without + the componentType property +- Added missing component-less SEQUENCE/SET objects dict duck-typing support +- Fixed unnecessary duplicate tags detection at NamesType.tagMap +- Fixed crash at SEQUENCE and SEQUENCE OF CER encoder when running + in schemaless mode +- Fixed Character types instantiation from OctetString type -- double + unicode decoding may have scrambled the data + +Revision 0.3.3, released 27-08-2017 +----------------------------------- + +- Improved ASN.1 types instantiation performance +- Improved BER/CER/DER decoder performance by not unconditionally casting + substrate into str/bytes. +- Fixed exponential index size growth bug when building ambiguous + NamedTypes tree +- Fixed constructed types decoding failure at BER codec if running + in schema-less mode +- Fixed crash on prettyPrint'ing a SEQUENCE with no defined components +- Fixed SetOf ordering at CER/DER encoder +- Fixed crash on conditional binascii module import +- Fix to TagSet hash value build + +Revision 0.3.2, released 04-08-2017 +----------------------------------- + +- Fixed SequenceOf/SetOf types initialization syntax to remain + backward compatible with pyasn1 0.2.* +- Rectified thread safety issues by moving lazy, run-time computation + into object initializer. +- Fixed .isValue property to return True for empty SetOf/SequenceOf + objects +- Fixed GeneralizedTime/UTCTime CER/DER codecs to actually get invoked +- Fixed DER/CER encoders handling optional SEQUENCE/SET fields containing + nested SEQUENCE/SET with optional fields. +- Fixed crash in SequenceOf/SetOf pretty printing and decoding (in some + cases) +- Fixed documentation markup issues. + +Revision 0.3.1, released 26-07-2017 +----------------------------------- + +- ASN.1 types __init__(), .clone() and .subtype() signatures + refactored into keyword arguments to simplify their signatures. +- ASN.1 types initialization refactored to minimize the use of + relatively expensive isNoValue() call +- Lazily pre-populate list of values of Sequence/Set/Choice types +- NamedTypes comparison made more efficient +- More efficient constraints computation and code clean up +- The __getitem__() implementation of some ASN.1 types & tag object + refactored for better performance +- BER/CER/DER value encoders refactored to produce either tuple of + bytes or octet-stream depending on what is more optimal +- Reduced the frequency of expensive isinstance() calls +- Tag-related classes optimized, refactored into properties and + documented. +- The NamedValues implementation refactored to mimic Python dict, its use + in ASN.1 types refactored into properties and better documented. + WARNING: this change introduces a deviation from original API. +- NamedType family of classes overhauled, optimized and documented. +- The `componentType` attribute of constructed ASN.1 types turned + read-only on instances. +- Sequence/Set DER/CER/DER decoder optimized to skip the case of + reordered components handling when not necessary. +- Tags and constraints-related getter methods refactored into read-only + instance attributes. +- The .hasValue() method refactored into .isValue property. All ASN.1 + objects now support them, not just scalars. +- The Real.{isInfinity, isPlusInfinity, isMinusInfinity} methods + refactored into properties and renamed into IsInf, IsPlusInf and isMinusInf +- The end-of-octets type refactored to ensure it is a singleton. Codecs + changed to rely on that for better performance. +- Codecs lookup made more efficient at BER/CER/DER decoder main loop by + assigning `typeId` to every ASN.1 type, not just ambiguous ones. +- The .getComponent*() methods of constructed ASN.1 types changed + to lazily instantiate underlying type rather than return `None`. + This should simplify its API as initialization like `X[0][1] = 2` becomes + possible. + WARNING: this change introduces a deviation from the original API. +- The .setComponent*() methods of SetOf/SequenceOf types changed not + to allow uninitialized "holes" inside the sequences of their components. + They now behave similarly to Python lists. + WARNING: this change introduces a deviation from the original API. +- Default and optional components en/decoding of Constructed type + refactored towards better efficiency and more control. +- OctetsString and Any decoder optimized to avoid creating ASN.1 + objects for chunks of substrate. Instead they now join substrate + chunks together and create ASN.1 object from it just once. +- The GeneralizedTime and UTCTime types now support to/from Python + datetime object conversion. +- Unit tests added for the `compat` sub-package. +- Fixed BitString named bits initialization bug. +- Fixed non-functional tag cache (when running Python 2) at DER decoder. +- Fixed chunked encoding restriction on DER encoder. +- Fixed SET components ordering at DER encoder. +- Fixed BIT STRING & OCTET STRING encoding to be always non-chunked (e.g. + primitive) at DER encoder +- Fixed `compat.integer.from_bytes()` behaviour on empty input. + +Revision 0.2.3, released 25-02-2017 +----------------------------------- + +- Improved SEQUENCE/SET/CHOICE decoding performance by maintaining a single shared + NamedType object for all instances of SEQUENCE/SET object. +- Improved INTEGER encoding/decoding by switching to Python's built-in + integer serialization functions. +- Improved BitString performance by rebasing it onto Python int type and leveraging + fast Integer serialization functions. +- BitString type usability improved in many ways: for example bitshifting and + numeric operation on BitString is now possible. +- Minor ObjectIdentifier type performance optimization. +- ASN.1 character types refactored to keep unicode contents internally + (rather than serialized octet stream) and duck-type it directly. +- ASN.1 OctetString initialized from a Python object performs bytes() + on it when running on Python 3 (used to do str() which is probably + less logical). +- Missing support for NoValue.__sizeof__ added. +- Added checks to make sure SEQUENCE/SET components being assigned + match the prototypes. +- Setter methods for constructed types consistently accept matchTags + and matchConstraints flags to control the strictness of inner + components compatibility verification. Previously, these checks + were tied to verifyConstraints flag, now they are all independent. +- General documentation improvements here and there. +- Fix to __reversed__() magic to make it returning an iterator. +- Test suite simplified and unified. +- The __all__ variable added to most of the Python modules. +- The "test" directory renamed into "tests" not to collide with + the "test" module. + +Revision 0.2.2, released 07-02-2017 +----------------------------------- + +- FIX TO A SECURITY WEAKNESS: define length only decoders could have successfully + processed indefinite length serialization. +- FIX TO A SECURITY WEAKNESS: canonical decoders (CER/DER) may have successfully + consumed non-canonical variations of (otherwise valid) serialization. +- Broken Enumerated subtyping fixed. + +Revision 0.2.1, released 05-02-2017 +----------------------------------- + +- FIX TO A SECURITY WEAKNESS: BER decoder improperly cached long tags. +- New "native" codec implemented to transform pyasn1 types to Python built-in types and back. +- Switched to new-style classes. +- Sphinx documentation added. +- BitString improvements: + + * simple string of binary digits is now supported as initializer + * default str() yields string of binary digits (used to yield str(tuple()) + * binValue and hexValue initializers added + * .asNumbers(), .asOctets() and asInteger() representation added + +- Components of constructed ASN.1 types can now be populated with + uninitialized ASN.1 objects by assigning either noValue sentinel or + setupComponent() function return in addition to now-legacy None sentinel. + This should improve code readability. +- NoValue class improved to become a singleton and catch more kinds + of access to it. +- Compatibility wrappers str2octs() and oct2strs() fixed to run over + iso-8859-1 encoding. +- Integer changed to emit Real instance if division produces a float. +- True division operation now supported by Integer type. +- The __contains__(), __reverse__() methods implemented for container types +- Iterator protocol support implemented for all container types. + Warning, warning, warning: this change may potentially affect backward + compatibility when: + + * user class overrides __getitem__() without overriding __iter__() + * when user code iterates over SEQUENCE object to get its components (now keys will be yielded) + +- Almost complete Python list and dict protocols added to SequenceOf/SetOf and + Sequence/Set respectively +- Fix to divmod operation implementation in Integer type. +- Fix to IntegerDecoder's precomputed value map on Python 3. +- Fix to base ASN.1 types to run in "unicode_literals" mode. +- Fix to composite constraints "+" operands ordering (AbstractConstraintSet.__radd__) +- Fix to constraints merge in .subtype() -- on merge existing constraints are + expanded to accommodate new constraints, not the other way round. When existing + constraints are wrapped in ConstraintsIntersection composite, additional + constraints being added on subtyping effectively further narrow the set of + allowed values, which aligns well with the notion of subtyping. +- Fix to NamedTypes methods to handle .getTagMap() returning None +- Fix to Set/Sequence.setDefaultComponents() to return self +- Copyright notice added to non-trivial source code files. +- Author's email changed, copyright extended to 2017 + +Revision 0.1.9, released 28-09-2015 +----------------------------------- + +- Wheel distribution format now supported. +- Extensions added to text files, CVS attic flushed. +- Fix to make uninitialized pyasn1 objects failing properly on hash(). +- Fix to ObjectIdentifier initialization from unicode string. +- Fix to CER/DER Boolean decoder - fail on non single-octet payload. + +Revision 0.1.8, released 22-06-2015 +----------------------------------- + +- ObjectIdentifier codec fixed to work properly with arc 0 and arc 2 values. +- Explicit limit on ObjectIdentifier arc value size removed. +- Unicode initializer support added to OctetString type and derivatives. +- New prettyPrintType() abstract method implemented to base pyasn1 types + to facilitate encoding errors analysis. +- The __str__() method implemented to Tag, TagSet and TagMap classes to + ease encoding errors troubleshooting. + easing encoding errors +- Fix to SEQUENCE and SET types to give them their private componentTypes + collection (which is a NamedTypes object) so that they won't collide in + a MT execution environment. +- Missing T61String,ISO646String character types and ObjectDescriptor useful + type added. +- Distribute is gone, switched to setuptools completely. +- Missing NamedValues.__repr__() added. +- The base.NoValue() class, that indicates uninitialized ASN.1 object, + made public. +- The base.NoValue() class instances now support __repr__() what makes + possible to perform repr() on uninitialized pyasn1 types objects. +- When comparing ASN.1 types, by-tag and/or by-constraints matching + can now be performed with the isSuperTypeOf()/isSameTypeWith() optional + flags. +- Constructed types now verify their consistency by invoking + isSameTypeWith(matchTags=True, matchConstraints=False) and + isSuperTypeOf(matchTags=False, matchConstraints=True) for each of their + components rather than isSuperTypeOf() as it used to be. Constriants check + could be enforced to isSameTypeWith() with the strictConstraints=True + constructed classes attribute. +- Constructed types can now be initialized with new .setComponents() method + which accepts both var-args and keyword-args. Default repr() modified to + reflect this change. +- NamedTypes() and NamedValues() made comparable. +- Test coverage extended to cover pyasn1 types __repr__() function. +- The abs(Integer()) & abs(Real()) operation now returns respective pyasn1 + type, not a Python type. +- More Python magic methods implementations added to Integer & Real classes + (e.g. __pos__, __neg__, __round__, __floor__, __ceil__, __trunc__) +- The Integer.__invert__ Python magic method implemented. +- The OctetString.__int__() and .__float__() magic methods implemented. +- Handle the case of null writer at Debug printer. +- BitString encoder/decoder performance improved. +- Built-in debugging is now based on Python logging module. +- Fix to NamedType.__repr__() to work properly. +- Fixes to __repr__() implementation of many built-in ASN.1 types to take into + account all of their initializers such as tagSet, subtypeSpec etc. +- String typed float initializer to REAL type now supported. +- Float typed mantissa initializer to REAL type for base 2 added. +- Encoding bases 8 and 16 support for REAL type binary encoder added. +- More strict CER/DER encoders added for GeneralizedTime and UTCTime types. +- Asn1Item.hasValue() added to easily distinguish initalized ASN.1 objects + from uninitialized ones (e.g. pure types). +- Fix to REAL type binary decoder to handle different bases and scale factor. +- Fix to TagSet.repr() to include [obsolete] baseTag information. +- Fix to broken REAL type decoding handling. +- Fix to BitString and OctetString decoders dealing with constructed + encoding -- it used to be possible to embed other types in substrate. +- DER codec hardened not to tolerate indefinite length encoding/decoding. +- Fix to end-of-octest sentinel handling: + + + require strict two-zeros sentinel encoding + + recognize EOO sentinel only when explicitly requested by caller + of the decoder via allowEoo=True parameter (warning: API change) + +Revision 0.1.7 +-------------- + +- License updated to vanilla BSD 2-Clause to ease package use + (http://opensource.org/licenses/BSD-2-Clause). +- Test suite made discoverable by unittest/unittest2 discovery feature. +- Fix to decoder working on indefinite length substrate -- end-of-octets + marker is now detected by both tag and value. Otherwise zero values may + interfere with end-of-octets marker. +- Fix to decoder to fail in cases where tagFormat indicates inappropriate + format for the type (e.g. BOOLEAN is always PRIMITIVE, SET is always + CONSTRUCTED and OCTET STRING is either of the two) +- Fix to REAL type encoder to force primitive encoding form encoding. +- Fix to CHOICE decoder to handle explicitly tagged, indefinite length + mode encoding +- Fix to REAL type decoder to handle negative REAL values correctly. Test + case added. + +Revision 0.1.6 +-------------- + +- The compact (valueless) way of encoding zero INTEGERs introduced in + 0.1.5 seems to fail miserably as the world is filled with broken + BER decoders. So we had to back off the *encoder* for a while. + There's still the IntegerEncoder.supportCompactZero flag which + enables compact encoding form whenever it evaluates to True. +- Report package version on debugging code initialization. + +Revision 0.1.5 +-------------- + +- Documentation updated and split into chapters to better match + web-site contents. +- Make prettyPrint() working for non-initialized pyasn1 data objects. It + used to throw an exception. +- Fix to encoder to produce empty-payload INTEGER values for zeros +- Fix to decoder to support empty-payload INTEGER and REAL values +- Fix to unit test suites imports to be able to run each from + their current directory + +Revision 0.1.4 +-------------- + +- Built-in codec debugging facility added +- Added some more checks to ObjectIdentifier BER encoder catching + posible 2^8 overflow condition by two leading sub-OIDs +- Implementations overriding the AbstractDecoder.valueDecoder method + changed to return the rest of substrate behind the item being processed + rather than the unprocessed substrate within the item (which is usually + empty). +- Decoder's recursiveFlag feature generalized as a user callback function + which is passed an uninitialized object recovered from substrate and + its uninterpreted payload. +- Catch inappropriate substrate type passed to decoder. +- Expose tagMap/typeMap/Decoder objects at DER decoder to uniform API. +- Obsolete __init__.MajorVersionId replaced with __init__.__version__ + which is now in-sync with distutils. +- Package classifiers updated. +- The __init__.py's made non-empty (rumors are that they may be optimized + out by package managers). +- Bail out gracefully whenever Python version is older than 2.4. +- Fix to Real codec exponent encoding (should be in 2's complement form), + some more test cases added. +- Fix in Boolean truth testing built-in methods +- Fix to substrate underrun error handling at ObjectIdentifier BER decoder +- Fix to BER Boolean decoder that allows other pre-computed + values besides 0 and 1 +- Fix to leading 0x80 octet handling in DER/CER/DER ObjectIdentifier decoder. + See http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf + +Revision 0.1.3 +-------------- + +- Include class name into asn1 value constraint violation exception. +- Fix to OctetString.prettyOut() method that looses leading zero when + building hex string. + +Revision 0.1.2 +-------------- + +- Fix to __long__() to actually return longs on py2k +- Fix to OctetString.__str__() workings of a non-initialized object. +- Fix to quote initializer of OctetString.__repr__() +- Minor fix towards ObjectIdentifier.prettyIn() reliability +- ObjectIdentifier.__str__() is aliased to prettyPrint() +- Exlicit repr() calls replaced with '%r' + +Revision 0.1.1 +-------------- + +- Hex/bin string initializer to OctetString object reworked + (in a backward-incompatible manner) +- Fixed float() infinity compatibility issue (affects 2.5 and earlier) +- Fixed a bug/typo at Boolean CER encoder. +- Major overhawl for Python 2.4 -- 3.2 compatibility: + + get rid of old-style types + + drop string module usage + + switch to rich comparation + + drop explicit long integer type use + + map()/filter() replaced with list comprehension + + apply() replaced with \*/\*\*args + + switched to use 'key' sort() callback function + + support both __nonzero__() and __bool__() methods + + modified not to use py3k-incompatible exception syntax + + getslice() operator fully replaced with getitem() + + dictionary operations made 2K/3K compatible + + base type for encoding substrate and OctetString-based types + is now 'bytes' when running py3k and 'str' otherwise + + OctetString and derivatives now unicode compliant. + + OctetString now supports two python-neutral getters: asOcts() & asInts() + + print OctetString content in hex whenever it is not printable otherwise + + in test suite, implicit relative import replaced with the absolute one + + in test suite, string constants replaced with numerics + +Revision 0.0.13 +--------------- + +- Fix to base10 normalization function that loops on univ.Real(0) + +Revision 0.0.13b +---------------- + +- ASN.1 Real type is now supported properly. +- Objects of Constructed types now support __setitem__() +- Set/Sequence objects can now be addressed by their field names (string index) + and position (integer index). +- Typo fix to ber.SetDecoder code that prevented with schema decoding + operation. +- Fix to explicitly tagged items decoding support. +- Fix to OctetString.prettyPrint() to better handle non-printable content. +- Fix to repr() workings of Choice objects. + +Revision 0.0.13a +---------------- + +- Major codec re-design. +- Documentation significantly improved. +- ASN.1 Any type is now supported. +- All example ASN.1 modules moved to separate pyasn1-modules package. +- Fix to initial sub-OID overflow condition detection an encoder. +- BitString initialization value verification improved. +- The Set/Sequence.getNameByPosition() method implemented. +- Fix to proper behaviour of PermittedAlphabetConstraint object. +- Fix to improper Boolean substrate handling at CER/DER decoders. +- Changes towards performance improvement: + + + all dict.has_key() & dict.get() invocations replaced with modern syntax + (this breaks compatibility with Python 2.1 and older). + + tag and tagset caches introduced to decoder + + decoder code improved to prevent unnecessary pyasn1 objects creation + + allow disabling components verification when setting components to + structured types, this is used by decoder whilst running with schema + mode. + + BER decoder for integer values now looks up a small set of pre-computed + substrate values to save on decoding. + + a few pre-computed values configured to ObjectIdentifier BER encoder. + + ChoiceDecoder split-off SequenceOf one to save on unnecessary checks. + + replace slow hasattr()/getattr() calls with isinstance() introspection. + + track the number of initialized components of Constructed types to save + on default/optional components initialization. + + added a shortcut ObjectIdentifier.asTuple() to be used instead of + __getitem__() in hotspots. + + use Tag.asTuple() and pure integers at tag encoder. + + introduce and use in decoder the baseTagSet attribute of the built-in + ASN.1 types. + +Revision 0.0.12a +---------------- + +- The individual tag/length/value processing methods of + encoder.AbstractItemEncoder renamed (leading underscore stripped) + to promote overloading in cases where partial substrate processing + is required. +- The ocsp.py, ldap.py example scripts added. +- Fix to univ.ObjectIdentifier input value handler to disallow negative + sub-IDs. + +Revision 0.0.11a +---------------- + +- Decoder can now treat values of unknown types as opaque OctetString. +- Fix to Set/SetOf type decoder to handle uninitialized scalar SetOf + components correctly. + +Revision 0.0.10a +---------------- + +- API versioning mechanics retired (pyasn1.v1 -> pyasn1) what makes + it possible to zip-import pyasn1 sources (used by egg and py2exe). + +Revision 0.0.9a +--------------- + +- Allow any non-zero values in Boolean type BER decoder, as it's in + accordnance with the standard. + +Revision 0.0.8a +--------------- + +- Integer.__index__() now supported (for Python 2.5+). +- Fix to empty value encoding in BitString encoder, test case added. +- Fix to SequenceOf decoder that prevents it skipping possible Choice + typed inner component. +- Choice.getName() method added for getting currently set component + name. +- OctetsString.prettyPrint() does a single str() against its value + eliminating an extra quotes. + +Revision 0.0.7a +--------------- + +- Large tags (>31) now supported by codecs. +- Fix to encoder to properly handle explicitly tagged untagged items. +- All possible value lengths (up to 256^126) now supported by encoders. +- Fix to Tag class constructor to prevent negative IDs. + +Revision 0.0.6a +--------------- + +- Make use of setuptools. +- Constraints derivation verification (isSuperTypeOf()/isSubTypeOf()) fixed. +- Fix to constraints comparation logic -- can't cmp() hash values as it + may cause false positives due to hash conflicts. + +Revision 0.0.5a +--------------- + +- Integer BER codec reworked fixing negative values encoding bug. +- clone() and subtype() methods of Constructed ASN.1 classes now + accept optional cloneValueFlag flag which controls original value + inheritance. The default is *not* to inherit original value for + performance reasons (this may affect backward compatibility). + Performance penalty may be huge on deeply nested Constructed objects + re-creation. +- Base ASN.1 types (pyasn1.type.univ.*) do not have default values + anymore. They remain uninitialized acting as ASN.1 types. In + this model, initialized ASN.1 types represent either types with + default value installed or a type instance. +- Decoders' prototypes are now class instances rather than classes. + This is to simplify initial value installation to decoder's + prototype value. +- Bugfix to BitString BER decoder (trailing bits not regarded). +- Bugfix to Constraints use as mapping keys. +- Bugfix to Integer & BitString clone() methods +- Bugix to the way to distinguish Set from SetOf at CER/DER SetOfEncoder +- Adjustments to make it running on Python 1.5. +- In tests, substrate constants converted from hex escaped literals into + octals to overcome indefinite hex width issue occuring in young Python. +- Minor performance optimization of TagSet.isSuperTagSetOf() method +- examples/sshkey.py added + +Revision 0.0.4a +--------------- + +* Asn1ItemBase.prettyPrinter() -> \*.prettyPrint() + +Revision 0.0.3a +--------------- + +* Simple ASN1 objects now hash to their Python value and don't + depend upon tag/constraints/etc. +* prettyIn & prettyOut methods of SimplleAsn1Object become public +* many syntax fixes + +Revision 0.0.2a +--------------- + +* ConstraintsIntersection.isSuperTypeOf() and + ConstraintsIntersection.hasConstraint() implemented +* Bugfix to NamedValues initialization code +* +/- operators added to NamedValues objects +* Integer.__abs__() & Integer.subtype() added +* ObjectIdentifier.prettyOut() fixes +* Allow subclass components at SequenceAndSetBase +* AbstractConstraint.__cmp__() dropped +* error.Asn1Error replaced with error.PyAsn1Error + +Revision 0.0.1a +--------------- + +* Initial public alpha release diff --git a/third_party/python/pyasn1/LICENSE b/third_party/python/pyasn1/LICENSE.rst similarity index 95% rename from third_party/python/pyasn1/LICENSE rename to third_party/python/pyasn1/LICENSE.rst index fac589b8cd75..02b45c430c71 100644 --- a/third_party/python/pyasn1/LICENSE +++ b/third_party/python/pyasn1/LICENSE.rst @@ -1,4 +1,4 @@ -Copyright (c) 2005-2013, Ilya Etingof +Copyright (c) 2005-2017, Ilya Etingof All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/third_party/python/pyasn1/MANIFEST.in b/third_party/python/pyasn1/MANIFEST.in index e8b3d36ce078..28d20e7074f7 100644 --- a/third_party/python/pyasn1/MANIFEST.in +++ b/third_party/python/pyasn1/MANIFEST.in @@ -1,3 +1,5 @@ -include CHANGES README LICENSE THANKS TODO -recursive-include test *.py -recursive-include doc *.html +include *.rst *.md +recursive-include tests *.py +recursive-include doc Makefile *.rst conf.py +prune doc/build +prune doc/source/.templates \ No newline at end of file diff --git a/third_party/python/pyasn1/PKG-INFO b/third_party/python/pyasn1/PKG-INFO index 5de78eceb04d..4454cb1caeb0 100644 --- a/third_party/python/pyasn1/PKG-INFO +++ b/third_party/python/pyasn1/PKG-INFO @@ -1,26 +1,33 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: pyasn1 -Version: 0.1.7 +Version: 0.3.7 Summary: ASN.1 types and codecs -Home-page: http://sourceforge.net/projects/pyasn1/ -Author: Ilya Etingof -Author-email: ilya@glas.net +Home-page: https://github.com/etingof/pyasn1 +Author: Ilya Etingof +Author-email: etingof@gmail.com License: BSD -Description: A pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208). +Description: Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208) Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: Science/Research Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.4 +Classifier: Programming Language :: Python :: 2.5 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Communications -Classifier: Topic :: Security :: Cryptography Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/third_party/python/pyasn1/README b/third_party/python/pyasn1/README deleted file mode 100644 index ffa3b57e5a3e..000000000000 --- a/third_party/python/pyasn1/README +++ /dev/null @@ -1,68 +0,0 @@ - -ASN.1 library for Python ------------------------- - -This is an implementation of ASN.1 types and codecs in Python programming -language. It has been first written to support particular protocol (SNMP) -but then generalized to be suitable for a wide range of protocols -based on ASN.1 specification. - -FEATURES --------- - -* Generic implementation of ASN.1 types (X.208) -* Fully standard compliant BER/CER/DER codecs -* 100% Python, works with Python 2.4 up to Python 3.3 (beta 1) -* MT-safe - -MISFEATURES ------------ - -* No ASN.1 compiler (by-hand ASN.1 spec compilation into Python code required) -* Codecs are not restartable - -INSTALLATION ------------- - -The pyasn1 package uses setuptools/distutils for installation. Thus do -either: - -$ easy_install pyasn1 - -or - -$ tar zxf pyasn1-0.1.3.tar.gz -$ cd pyasn1-0.1.3 -$ python setup.py install -$ cd test -$ python suite.py # run unit tests - -OPERATION ---------- - -Perhaps a typical use would involve [by-hand] compilation of your ASN.1 -specification into pyasn1-backed Python code at your application. - -For more information on pyasn1 APIs, please, refer to the -doc/pyasn1-tutorial.html file in the distribution. - -Also refer to example modules. Take a look at pyasn1-modules package -- maybe -it already holds something useful to you. - -AVAILABILITY ------------- - -The pyasn1 package is distributed under terms and conditions of BSD-style -license. See LICENSE file in the distribution. Source code is freely -available from: - -http://pyasn1.sf.net - - -FEEDBACK --------- - -Please, send your comments and fixes to mailing lists at project web site. - -=-=-= -mailto: ilya@glas.net diff --git a/third_party/python/pyasn1/README.md b/third_party/python/pyasn1/README.md new file mode 100644 index 000000000000..f0b72b49088a --- /dev/null +++ b/third_party/python/pyasn1/README.md @@ -0,0 +1,184 @@ + +ASN.1 library for Python +------------------------ +[![PyPI](https://img.shields.io/pypi/v/pyasn1.svg?maxAge=2592000)](https://pypi.python.org/pypi/pyasn1) +[![Python Versions](https://img.shields.io/pypi/pyversions/pyasn1.svg)](https://pypi.python.org/pypi/pyasn1/) +[![Build status](https://travis-ci.org/etingof/pyasn1.svg?branch=master)](https://secure.travis-ci.org/etingof/pyasn1) +[![Coverage Status](https://img.shields.io/codecov/c/github/etingof/pyasn1.svg)](https://codecov.io/github/etingof/pyasn1) +[![GitHub license](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/etingof/pyasn1/master/LICENSE.txt) + +This is a free and open source implementation of ASN.1 types and codecs +as a Python package. It has been first written to support particular +protocol (SNMP) but then generalized to be suitable for a wide range +of protocols based on +[ASN.1 specification](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.208-198811-W!!PDF-E&type=items). + +Features +-------- + +* Generic implementation of ASN.1 types (X.208) +* Standards compliant BER/CER/DER codecs +* Dumps/loads ASN.1 structures from Python types +* 100% Python, works with Python 2.4 up to Python 3.6 +* MT-safe +* Contributed ASN.1 compiler [Asn1ate](https://github.com/kimgr/asn1ate) + +Why using pyasn1 +---------------- + +ASN.1 solves the data serialization problem. This solution was +designed long ago by the wise Ancients. Back then, they did not +have the luxury of wasting bits. That is why ASN.1 is designed +to serialize data structures of unbounded complexity into +something compact and efficient when it comes to processing +the data. + +That probably explains why many network protocols and file formats +still rely on the 30+ years old technology. Including a number of +high-profile Internet protocols and file formats. + +Quite a number of books cover the topic of ASN.1. +[Communication between heterogeneous systems](http://www.oss.com/asn1/dubuisson.html) +by Olivier Dubuisson is one of those high quality books freely +available on the Internet. + +The pyasn1 package is designed to help Python programmers tackling +network protocols and file formats at the comfort of their Python +prompt. The tool struggles to capture all aspects of a rather +complicated ASN.1 system and to represent it on the Python terms. + +How to use pyasn1 +----------------- + +With pyasn1 you can build Python objects from ASN.1 data structures. +For example, the following ASN.1 data structure: + +```bash +Record ::= SEQUENCE { + id INTEGER, + room [0] INTEGER OPTIONAL, + house [1] INTEGER DEFAULT 0 +} +``` + +Could be expressed in pyasn1 like this: + +```python +class Record(Sequence): + componentType = NamedTypes( + NamedType('id', Integer()), + OptionalNamedType( + 'room', Integer().subtype( + implicitTag=Tag(tagClassContext, tagFormatSimple, 0) + ) + ), + DefaultedNamedType( + 'house', Integer(0).subtype( + implicitTag=Tag(tagClassContext, tagFormatSimple, 1) + ) + ) + ) +``` + +It is in the spirit of ASN.1 to take abstract data description +and turn it into a programming language specific form. +Once you have your ASN.1 data structure expressed in Python, you +can use it along the lines of similar Python type (e.g. ASN.1 +`SET` is similar to Python `dict`, `SET OF` to `list`): + +```python +>>> record = Record() +>>> record['id'] = 123 +>>> record['room'] = 321 +>>> print(record.prettyPrint()) +Record: + id=123 + room=321 +>>> +``` + +Part of the power of ASN.1 comes from its serialization features. You +can serialize your data structure and send it over the network. + +```python +>>> from pyasn1.codec.der.encoder import encode +>>> substrate = encode(record) +>>> hexdump(substrate) +00000: 30 07 02 01 7B 80 02 01 41 +``` + +Conversely, you can turn serialized ASN.1 content, as received from +network or read from a file, into a Python object which you can +introspect, modify, encode and send back. + +```python +>>> from pyasn1.codec.der.decoder import decode +>>> received_record, rest_of_substrate = decode(substrate, asn1Spec=Record()) +>>> +>>> for field in received_record: +>>> print('{} is {}'.format(field, received_record[field])) +id is 123 +room is 321 +house is 0 +>>> +>>> record == received_record +True +>>> received_record.update(room=123) +>>> substrate = encode(received_record) +>>> hexdump(substrate) +00000: 30 06 02 01 7B 80 01 7B +``` + +The pyasn1 classes struggle to emulate their Python prototypes (e.g. int, +list, dict etc.). But ASN.1 types exhibit more complicated behaviour. +To make life easier for a Pythonista, they can turn their pyasn1 +classes into Python built-ins: + +```python +>>> from pyasn1.codec.native.encoder import encode +>>> encode(record) +{'id': 123, 'room': 321, 'house': 0} +``` + +Or vice-versa -- you can initialize an ASN.1 structure from a tree of +Python objects: + +```python +>>> from pyasn1.codec.native.decoder import decode +>>> record = decode({'id': 123, 'room': 321, 'house': 0}, asn1Spec=Record()) +>>> print(record.prettyPrint()) +Record: + id=123 + room=321 +>>> +``` + +With ASN.1 design, serialization codecs are decoupled from data objects, +so you could turn every single ASN.1 object into many different +serialized forms. As of this moment, pyasn1 supports BER, DER, CER and +Python built-ins codecs. The extremely compact PER encoding is expected +to be introduced in the upcoming pyasn1 release. + +More information on pyasn1 APIs can be found in the +[documentation](http://pyasn1.sourceforge.net), +compiled ASN.1 modules for different protocols and file formats +could be found in the pyasn1-modules +[repo](https://github.com/etingof/pyasn1-modules). + +How to get pyasn1 +----------------- + +The pyasn1 package is distributed under terms and conditions of 2-clause +BSD [license](http://pyasn1.sourceforge.net/license.html). Source code is freely +available as a GitHub [repo](https://github.com/etingof/pyasn1). + +You could `pip install pyasn1` or download it from [PyPI](https://pypi.python.org/pypi/pyasn1). + +If something does not work as expected, +[open an issue](https://github.com/etingof/pyasn1/issues) at GitHub or +post your question [on Stack Overflow](http://stackoverflow.com/questions/ask) +or try browsing pyasn1 +[mailing list archives](https://sourceforge.net/p/pyasn1/mailman/pyasn1-users/). + +Copyright (c) 2005-2017, [Ilya Etingof](mailto:etingof@gmail.com). +All rights reserved. diff --git a/third_party/python/pyasn1/THANKS b/third_party/python/pyasn1/THANKS deleted file mode 100644 index 4de1713c0332..000000000000 --- a/third_party/python/pyasn1/THANKS +++ /dev/null @@ -1,4 +0,0 @@ -Denis S. Otkidach -Gregory Golberg -Bud P. Bruegger -Jacek Konieczny diff --git a/third_party/python/pyasn1/TODO b/third_party/python/pyasn1/TODO deleted file mode 100644 index 0ee211c2a43b..000000000000 --- a/third_party/python/pyasn1/TODO +++ /dev/null @@ -1,36 +0,0 @@ -* Specialize ASN.1 character and useful types -* Come up with simpler API for deeply nested constructed objects - addressing - -ber.decoder: -* suspend codec on underrun error ? -* class-static components map (in simple type classes) -* present subtypes ? -* component presence check wont work at innertypeconst -* add the rest of ASN1 types/codecs -* type vs value, defaultValue - -ber.encoder: -* Asn1Item.clone() / shallowcopy issue -* large length encoder? -* codec restart -* preserve compatible API whenever stateful codec gets implemented -* restartable vs incremental -* plan: make a stateless univeral decoder, then convert it to restartable - then to incremental - -type.useful: -* may need to implement prettyIn/Out - -type.char: -* may need to implement constraints - -type.univ: -* simpler API to constructed objects: value init, recursive - -type.namedtypes -* type vs tagset name convention - -general: - -* how untagged TagSet should be initialized? diff --git a/third_party/python/pyasn1/TODO.rst b/third_party/python/pyasn1/TODO.rst new file mode 100644 index 000000000000..5c79ee7cdfdd --- /dev/null +++ b/third_party/python/pyasn1/TODO.rst @@ -0,0 +1,92 @@ + +Things to be done +================= + +Big things to tackle, anyone interested is welcome to fork pyasn1, work on +it and come up with a PR! + +New codecs +---------- + +* PER +* OER +* XER +* LWER +* JSON (alinged with existing experimental schemas) + +Lazy codecs +----------- + +Implement a thin layer over base types to cache pieces +of substrate being decoded till the very moment of ASN.1 +object access in the parse tree. + +Codecs generator interface +-------------------------- + +For indefinite length or chunked encoding mode, make codecs +iterable producing/consuming substrate/objects. + +ASN.1 schema compiler +--------------------- + +Ideally, the compiler should parse modern schema files and be +designed to emit code for arbitrary languages (including SQL). + +Base types +---------- + +Implement X.680 constructs, including information schema. + +Examples +-------- + +Add examples, including advanced/obscure use cases. + +Documentation +------------- + +Document more API, add notes and example snippets. + +More fresh modules +------------------ + +Compile and ship more Pythonized ASN.1 modules for +various ASN.1-based protocols (e.g. Kerberos etc). +Refresh outdated modules in pyasn1-packages. + +Minor, housekeeping things +-------------------------- + +* more PEP8'ing at places +* consider simplifying repr(), otherwise it tend to be too hard to grasp +* Specialize ASN.1 character and useful types + +* ber.decoder: + + * suspend codec on underrun error ? + * present subtypes ? + * component presence check wont work at innertypeconst + * type vs value, defaultValue + +* ber.encoder: + + * Asn1Item.clone() / shallowcopy issue + * large length encoder? + * lookup type by tag first to allow custom codecs for non-base types + +* type.useful: + + * may need to implement prettyIn/Out + +* type.char: + + * may need to implement constraints + +* type.namedtypes + + * type vs tagset name convention + +* how untagged TagSet should be initialized? + +* type and codecs for Real needs refactoring diff --git a/third_party/python/pyasn1/doc/Makefile b/third_party/python/pyasn1/doc/Makefile new file mode 100644 index 000000000000..214532e67163 --- /dev/null +++ b/third_party/python/pyasn1/doc/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyASN1.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyASN1.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/PyASN1" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyASN1" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/third_party/python/pyasn1/doc/codecs.html b/third_party/python/pyasn1/doc/codecs.html deleted file mode 100644 index 9c2c36ed6f05..000000000000 --- a/third_party/python/pyasn1/doc/codecs.html +++ /dev/null @@ -1,503 +0,0 @@ - - -PyASN1 codecs - - - - -
- - - - -
-

-2. PyASN1 Codecs -

- -

-In ASN.1 context, -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 -. -

- -

-As of this writing, codecs implemented in pyasn1 are all stateless, mostly -to keep the code simple. -

- -

-The pyasn1 package currently supports -BER codec and -its variations -- -CER and -DER. -More ASN.1 codecs are planned for implementation in the future. -

- - -

-2.1 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: -

- -
-
->>> 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. -

- -
-
->>> 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. -

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

-2.2 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. -

- -
-
->>> 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. -

- -
-
->>> 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 handbook, when an ASN.1 type is implicitly -tagged, previous outermost tag is lost and never appears in substrate. -If it is the base tag that gets lost, decoder is unable to pick type-specific -value decoder at its table of built-in types, and therefore recover -the value part, based only on the information contained in substrate. The -approach taken by pyasn1 decoder is to use a prototype pyasn1 type object (or -a set of them) to 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 paper). -

- -
-
->>> 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: -

- -
-
->>> 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. -

- -
-
->>> from pyasn1.type import univ, constraint
->>> from pyasn1.codec.ber import encoder, decoder
->>> class DialDigit(univ.Integer):
-...   subtypeSpec = constraint.ValueRangeConstraint(0,9)
->>> substrate = encoder.encode(univ.Integer(13))
->>> decoder.decode(substrate)
-(Integer(13), b'')
->>> decoder.decode(substrate, asn1Spec=DialDigit())
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ValueRangeConstraint(0, 9) failed at: 13
->>> 
-
-
- -

-Similarily to encoders, to use CER or DER decoders application has to -explicitly import and call them - all APIs are compatible. -

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

-2.2.1 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: -

- -
-
->>> from pyasn1.type import univ, namedtype
->>> class CodeOrMessage(univ.Choice):
-...   componentType = namedtype.NamedTypes(
-...     namedtype.NamedType('code', univ.Integer()),
-...     namedtype.NamedType('message', univ.OctetString())
-...   )
->>>
->>> codeOrMessage = CodeOrMessage()
->>> codeOrMessage.setComponentByName('message', 'my string value')
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
- message=b'my string value'
->>>
-
-
- -

-Let's now encode this Choice object and then decode its substrate -with and without pyasn1 specification object: -

- -
-
->>> 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 paper, 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. -

- -
-
->>> 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: -

- -
-
->>> 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 for more information. -

- - -

-2.2.2 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. -

- -
-
->>> 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/third_party/python/pyasn1/doc/constraints.html b/third_party/python/pyasn1/doc/constraints.html deleted file mode 100644 index 53da1addffe0..000000000000 --- a/third_party/python/pyasn1/doc/constraints.html +++ /dev/null @@ -1,436 +0,0 @@ - - -PyASN1 subtype constraints - - - - -
- - - - -
- -

-1.4 PyASN1 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. -

- - -

-1.4.1 Single value constraint -

- -

-This kind of constraint allows for limiting type to a finite, specified set -of values. -

- -
-
-DialButton ::= OCTET STRING (
-  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
-)
-
-
- -

-Its pyasn1 implementation would look like: -

- -
-
->>> from pyasn1.type import constraint
->>> c = constraint.SingleValueConstraint(
-  '0','1','2','3','4','5','6','7','8','9'
-)
->>> c
-SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
->>> c('0')
->>> c('A')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError: 
-  SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
->>> 
-
-
- -

-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. -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class DialButton(univ.OctetString):
-...   subtypeSpec = constraint.SingleValueConstraint(
-...       '0','1','2','3','4','5','6','7','8','9'
-...   )
->>> DialButton('0')
-DialButton(b'0')
->>> DialButton('A')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
->>> 
-
-
- -

-Constrained pyasn1 value object can never hold a violating value. -

- - -

-1.4.2 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. -

- -
-
-Teenagers ::= INTEGER (13..19)
-
-
- -

-And in pyasn1 terms: -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class Teenagers(univ.Integer):
-...   subtypeSpec = constraint.ValueRangeConstraint(13, 19)
->>> Teenagers(14)
-Teenagers(14)
->>> Teenagers(20)
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ValueRangeConstraint(13, 19) failed at: 20
->>> 
-
-
- -

-Value range constraint usually applies numeric types. -

- - -

-1.4.3 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. -

- -
-
-TwoBits ::= BIT STRING (SIZE (2))
-
-
- -

-Express the same grammar in pyasn1: -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class TwoBits(univ.BitString):
-...   subtypeSpec = constraint.ValueSizeConstraint(2, 2)
->>> TwoBits((1,1))
-TwoBits("'11'B")
->>> TwoBits((1,1,0))
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ValueSizeConstraint(2, 2) failed at: (1, 1, 0)
->>> 
-
-
- -

-Size constraint can be applied to potentially massive values - bit or octet -strings, SEQUENCE OF/SET OF values. -

- - -

-1.4.4 Alphabet constraint -

- -

-The permitted alphabet constraint is similar to Single value constraint -but constraint applies to individual characters of a value. -

- -
-
-MorseCode ::= PrintableString (FROM ("."|"-"|" "))
-
-
- -

-And in pyasn1: -

- -
-
->>> from pyasn1.type import char, constraint
->>> class MorseCode(char.PrintableString):
-...   subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ")
->>> MorseCode("...---...")
-MorseCode('...---...')
->>> MorseCode("?")
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  PermittedAlphabetConstraint(".", "-", " ") failed at: "?"
->>> 
-
-
- -

-Current implementation does not handle ranges of characters in constraint -(FROM "A".."Z" syntax), one has to list the whole set in a range. -

- - -

-1.4.5 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: -

- -
-
-PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11)
-
-
- -

-Constraint intersection object serves the logic above: -

- -
-
->>> from pyasn1.type import char, constraint
->>> class PhoneNumber(char.NumericString):
-...   subtypeSpec = constraint.ConstraintsIntersection(
-...     constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
-...     constraint.ValueSizeConstraint(11, 11)
-...   )
->>> PhoneNumber('79039343212')
-PhoneNumber('79039343212')
->>> PhoneNumber('?9039343212')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsIntersection(
-    PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
-      ValueSizeConstraint(11, 11)) failed at: 
-   PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212"
->>> PhoneNumber('9343212')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsIntersection(
-    PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
-      ValueSizeConstraint(11, 11)) failed at:
-  ValueSizeConstraint(10, 10) failed at: "9343212"
->>>
-
-
- -

-Union of constraints works by making sure that a value is compliant -to any of the constraint in a set. For instance: -

- -
-
-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: -

- -
-
->>> from pyasn1.type import char, constraint
->>> class CapitalOrSmall(char.IA5String):
-...   subtypeSpec = constraint.ConstraintsUnion(
-...     constraint.PermittedAlphabetConstraint('A','B','C'),
-...     constraint.PermittedAlphabetConstraint('a','b','c')
-...   )
->>> CapitalOrSmall('ABBA')
-CapitalOrSmall('ABBA')
->>> CapitalOrSmall('abba')
-CapitalOrSmall('abba')
->>> CapitalOrSmall('Abba')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'),
-    PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba"
->>>
-
-
- -

-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. -

- -
-
-NoZero ::= INTEGER (ALL EXCEPT 0)
-
-
- -

-In pyasn1 the above definition would read: -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class NoZero(univ.Integer):
-...   subtypeSpec = constraint.ConstraintsExclusion(
-...     constraint.SingleValueConstraint(0)
-...   )
->>> NoZero(1)
-NoZero(1)
->>> NoZero(0)
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0
->>>
-
-
- -

-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. -

- - -

-1.5 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): -

- -
-
->>> 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. -

- -
- -
-
- - diff --git a/third_party/python/pyasn1/doc/constructed.html b/third_party/python/pyasn1/doc/constructed.html deleted file mode 100644 index 88de750758a5..000000000000 --- a/third_party/python/pyasn1/doc/constructed.html +++ /dev/null @@ -1,377 +0,0 @@ - - -PyASN1 Constructed types - - - - -
- - - - -
- -

-1.3 PyASN1 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. -

- - -

-1.3.1 Sequence and Set types -

- -

-The Sequence and Set types have many similar properties: -

-
    -
  • they 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, Sequence type guarantees the ordering of Sequence value components -to match their declaration order. By contrast, components of the -Set type can be ordered to best suite application's needs. -

- -
-
-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. -

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

- -
-
->>> record = Record()
->>> record.setComponentByName('id', 123)
->>> print(record.prettyPrint())
-Record:
- id=123
->>> 
->>> record.setComponentByPosition(1, 321)
->>> print(record.prettyPrint())
-Record:
- id=123
- room=321
->>>
->>> record.setDefaultComponents()
->>> print(record.prettyPrint())
-Record:
- id=123
- room=321
- house=0
-
-
- -

-Inner components of pyasn1 Sequence/Set objects could be accessed using the -following methods: -

- -
-
->>> record.getComponentByName('id')
-Integer(123)
->>> record.getComponentByPosition(1)
-Integer(321)
->>> record[2]
-Integer(0)
->>> for idx in range(len(record)):
-...   print(record.getNameByPosition(idx), record.getComponentByPosition(idx))
-id 123
-room 321
-house 0
->>>
-
-
- -

-The Set type share all the properties of Sequence type, and additionally -support by-tag component addressing (as all Set components have distinct -types). -

- -
-
->>> from pyasn1.type import univ, namedtype, tag
->>> class Gamer(univ.Set):
-...   componentType = namedtype.NamedTypes(
-...     namedtype.NamedType('score', univ.Integer()),
-...     namedtype.NamedType('player', univ.OctetString()),
-...     namedtype.NamedType('id', univ.ObjectIdentifier())
-...   )
->>> gamer = Gamer()
->>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343)
->>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal')
->>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2))
->>> print(gamer.prettyPrint())
-Gamer:
- score=121343
- player=b'Pascal'
- id=1.3.7.2
->>>
-
-
- - -

-1.3.2 SequenceOf and SetOf types -

- -

-Both, SequenceOf and SetOf types resemble an unlimited size list of components. -All the components must be of the same type. -

- -
-
-Progression ::= SEQUENCE OF INTEGER
-
-arithmeticProgression Progression ::= { 1, 3, 5, 7 }
-
-
- -

-SequenceOf and SetOf types are expressed by the very similar pyasn1 type -objects. Their components can only be addressed by position and they -both have a property of automatic resize. -

- -

-To specify inner component type, the componentType class attribute -should refer to another pyasn1 type object. -

- -
-
->>> from pyasn1.type import univ
->>> class Progression(univ.SequenceOf):
-...   componentType = univ.Integer()
->>> arithmeticProgression = Progression()
->>> arithmeticProgression.setComponentByPosition(1, 111)
->>> print(arithmeticProgression.prettyPrint())
-Progression:
--empty- 111
->>> arithmeticProgression.setComponentByPosition(0, 100)
->>> print(arithmeticProgression.prettyPrint())
-Progression:
-100 111
->>>
->>> for idx in range(len(arithmeticProgression)):
-...    arithmeticProgression.getComponentByPosition(idx)
-Integer(100)
-Integer(111)
->>>
-
-
- -

-Any scalar or constructed pyasn1 type object can serve as an inner component. -Missing components are prohibited in SequenceOf/SetOf value objects. -

- - -

-1.3.3 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. -

- -
-
-CodeOrMessage ::= CHOICE {
-  code    INTEGER,
-  message OCTET STRING
-}
-
-
- -

-In pyasn1 implementation, Choice object behaves like Set but accepts only -a single inner component at a time. It also offers a few additional methods -specific to its behaviour. -

- -
-
->>> from pyasn1.type import univ, namedtype
->>> class CodeOrMessage(univ.Choice):
-...   componentType = namedtype.NamedTypes(
-...     namedtype.NamedType('code', univ.Integer()),
-...     namedtype.NamedType('message', univ.OctetString())
-...   )
->>>
->>> codeOrMessage = CodeOrMessage()
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
->>> codeOrMessage.setComponentByName('code', 123)
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
- code=123
->>> codeOrMessage.setComponentByName('message', 'my string value')
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
- message=b'my string value'
->>>
-
-
- -

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

- -
-
->>> codeOrMessage.getName()
-'message'
->>> codeOrMessage.getComponent()
-OctetString(b'my string value')
->>>
-
-
- - -

-1.3.4 Any type -

- -

-The ASN.1 ANY type is a kind of wildcard or placeholder that matches -any other type without knowing it in advance. Like CHOICE type, ANY -has no base tag. -

- -
-
-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 Any value object share the properties of -pyasn1 OctetString object. -

- -
-
->>> 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. -

- -
- -
-
- - diff --git a/third_party/python/pyasn1/doc/intro.html b/third_party/python/pyasn1/doc/intro.html deleted file mode 100644 index 3ff18b6ae5b8..000000000000 --- a/third_party/python/pyasn1/doc/intro.html +++ /dev/null @@ -1,156 +0,0 @@ - - -PyASN1 reference manual - - - - -
- - - - -
- -

-PyASN1 reference manual -

- -

-written by Ilya Etingof, 2011-2012 -

- -

-Free and open-source pyasn1 library makes it easier for programmers and -network engineers to develop, debug and experiment with ASN.1-based protocols -using Python programming language as a tool. -

- -

-Abstract Syntax Notation One -(ASN.1) -is a set of - -ITU standards concered with provisioning instrumentation for developing -data exchange protocols in a robust, clear and interoperabable way for -various IT systems and applications. Most of the efforts are targeting the -following areas: -

    -
  • Data structures: the standard introduces a collection of basic data types -(similar to integers, bits, strings, arrays and records in a programming -language) that can be used for defining complex, possibly nested data -structures representing domain-specific data units. -
  • Serialization protocols: domain-specific data units expressed in ASN.1 -types could be converted into a series of octets for storage or transmission -over the wire and then recovered back into their structured form on the -receiving end. This process is immune to various hardware and software -related dependencies. -
  • Data description language: could be used to describe particular set of -domain-specific data structures and their relationships. Such a description -could be passed to an ASN.1 compiler for automated generation of program -code that represents ASN.1 data structures in language-native environment -and handles data serialization issues. -
-

- -

-This tutorial and algorithms, implemented by pyasn1 library, are -largely based on the information read in the book - -ASN.1 - Communication between heterogeneous systems -by Olivier Dubuisson. Another relevant resource is - -A Layman's Guide to a Subset of ASN.1, BER, and DER by Burton S. Kaliski. -It's advised to refer to these books for more in-depth knowledge on the -subject of ASN.1. -

- -

-As of this writing, pyasn1 library implements most of standard ASN.1 data -structures in a rather detailed and feature-rich manner. Another highly -important capability of the library is its data serialization facilities. -The last component of the standard - ASN.1 compiler is planned for -implementation in the future. -

- -

-The pyasn1 library was designed to follow the pre-1995 ASN.1 specification -(also known as X.208). Later, post 1995, revision (X.680) introduced -significant changes most of which have not yet been supported by pyasn1. -

- -

-Table of contents -

- -

-

- -

-Although pyasn1 software is almost a decade old and used in many production -environments, it still may have bugs and non-implemented pieces. Anyone -who happens to run into such defect is welcome to complain to -pyasn1 mailing list -or better yet fix the issue and send -me the patch. -

- -

-Typically, pyasn1 is used for building arbitrary protocol support into -various applications. This involves manual translation of ASN.1 data -structures into their pyasn1 implementations. To save time and effort, -data structures for some of the popular protocols are pre-programmed -and kept for further re-use in form of the - -pyasn1-modules package. For instance, many structures for PKI (X.509, -PKCS#*, CRMF, OCSP), LDAP and SNMP are present. -Applications authors are advised to import and use relevant modules -from that package whenever needed protocol structures are already -there. New protocol modules contributions are welcome. -

- -

-And finally, the latest pyasn1 package revision is available for free -download from -project home and -also from the -Python package repository. -

- -
- -
-
- - diff --git a/third_party/python/pyasn1/doc/pyasn1-tutorial.html b/third_party/python/pyasn1/doc/pyasn1-tutorial.html deleted file mode 100644 index 2eb82f1e936d..000000000000 --- a/third_party/python/pyasn1/doc/pyasn1-tutorial.html +++ /dev/null @@ -1,2405 +0,0 @@ - - -PyASN1 programmer's manual - - - - -
- - - - -
- -

-PyASN1 programmer's manual -

- -

-written by Ilya Etingof, 2011-2012 -

- -

-Free and open-source pyasn1 library makes it easier for programmers and -network engineers to develop, debug and experiment with ASN.1-based protocols -using Python programming language as a tool. -

- -

-Abstract Syntax Notation One -(ASN.1) -is a set of - -ITU standards concered with provisioning instrumentation for developing -data exchange protocols in a robust, clear and interoperabable way for -various IT systems and applications. Most of the efforts are targeting the -following areas: -

    -
  • Data structures: the standard introduces a collection of basic data types -(similar to integers, bits, strings, arrays and records in a programming -language) that can be used for defining complex, possibly nested data -structures representing domain-specific data units. -
  • Serialization protocols: domain-specific data units expressed in ASN.1 -types could be converted into a series of octets for storage or transmission -over the wire and then recovered back into their structured form on the -receiving end. This process is immune to various hardware and software -related dependencies. -
  • Data description language: could be used to describe particular set of -domain-specific data structures and their relationships. Such a description -could be passed to an ASN.1 compiler for automated generation of program -code that represents ASN.1 data structures in language-native environment -and handles data serialization issues. -
-

- -

-This tutorial and algorithms, implemented by pyasn1 library, are -largely based on the information read in the book - -ASN.1 - Communication between heterogeneous systems -by Olivier Dubuisson. Another relevant resource is - -A Layman's Guide to a Subset of ASN.1, BER, and DER by Burton S. Kaliski. -It's advised to refer to these books for more in-depth knowledge on the -subject of ASN.1. -

- -

-As of this writing, pyasn1 library implements most of standard ASN.1 data -structures in a rather detailed and feature-rich manner. Another highly -important capability of the library is its data serialization facilities. -The last component of the standard - ASN.1 compiler is planned for -implementation in the future. -

- -

-The pyasn1 library was designed to follow the pre-1995 ASN.1 specification -(also known as X.208). Later, post 1995, revision (X.680) introduced -significant changes most of which have not yet been supported by pyasn1. -

- -

-Table of contents -

- -

-

- - - -

-1. 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. -

- -
-
->>> 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: -

- -
-
->>> from pyasn1.type import univ
->>> asn1IntegerType = univ.Integer()
->>> asn1IntegerType - 2
-...
-pyasn1.error.PyAsn1Error: No value for __coerce__()
-
-
- - -

-1.1 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. -

- - -

-1.1.1 Boolean type -

- -

-This is the simplest type those values could be either True or False. -

- -
-
-;; type specification
-FunFactorPresent ::= BOOLEAN
-
-;; values declaration and assignment
-pythonFunFactor FunFactorPresent ::= TRUE
-cobolFunFactor FunFactorPresent :: FALSE
-
-
- -

-And here's pyasn1 version of it: -

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

-1.1.2 Null type -

- -

-The NULL type is sometimes used to express the absense of any information. -

- -
-
-;; type specification
-Vote ::= CHOICE {
-  agreed BOOLEAN,
-  skip NULL
-}
-
- -;; value declaration and assignment -myVote Vote ::= skip:NULL - - -

-We will explain the CHOICE type later in this paper, meanwhile the NULL -type: -

- -
-
->>> from pyasn1.type import univ
->>> skip = univ.Null()
->>> skip
-Null('')
->>>
-
-
- - -

-1.1.3 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. -

- -
-
-;; values specification
-age-of-universe INTEGER ::= 13750000000
-mean-martian-surface-temperature INTEGER ::= -63
-
-
- -

-A rather strigntforward mapping into pyasn1: -

- -
-
->>> 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. -

- -
-
-Temperature ::= INTEGER {
-  freezing(0),
-  boiling(100) 
-}
-
-
- -

-The Temperature type expressed in pyasn1: -

- -
-
->>> 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 this paper). -

- - -

-1.1.4 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. -

- -
-
-error-status ::= ENUMERATED {
-  no-error(0),
-  authentication-error(10),
-  authorization-error(20),
-  general-failure(51)
-}
-
-
- -

-When constructing Enumerated type we will use two pyasn1 features: values -labels (as mentioned above) and value constraint (will be described in -more details later on). -

- -
-
->>> 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. -

- - -

-1.1.5 Real type -

- -

-Values of the Real type are a three-component tuple of mantissa, base and -exponent. All three are integers. -

- -
-
-pi ::= REAL { mantissa 314159, base 10, exponent -5 }
-
-
- -

-Corresponding pyasn1 objects can be initialized with either a three-component -tuple or a Python float. Infinite values could be expressed in a way, -compatible with Python float type. - -

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

- - -

-1.1.6 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. -

- -
-
-public-key BIT STRING ::= '1010111011110001010110101101101
-                           1011000101010000010110101100010
-                           0110101010000111101010111111110'B
-
-signature  BIT STRING ::= 'AF01330CD932093392100B39FF00DE0'H
-
-
- -

-The pyasn1 BitString objects can initialize from native ASN.1 notation -(base 2 or base 16 strings) or from a Python tuple of binary components. -

- -
-
->>> from pyasn1.type import univ
->>> publicKey = univ.BitString(
-...          "'1010111011110001010110101101101"
-...          "1011000101010000010110101100010"
-...          "0110101010000111101010111111110'B"
-)
->>> publicKey
-BitString("'10101110111100010101101011011011011000101010000010110101100010\
-0110101010000111101010111111110'B")
->>> signature = univ.BitString(
-...          "'AF01330CD932093392100B39FF00DE0'H"
-... )
->>> signature
-BitString("'101011110000000100110011000011001101100100110010000010010011001\
-1100100100001000000001011001110011111111100000000110111100000'B")
->>> fingerprint = univ.BitString(
-...          (1, 0, 1, 1 ,0, 1, 1, 1, 0, 1, 0, 1)
-... )
->>> fingerprint
-BitString("'101101110101'B")
->>>
-
-
- -

-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. -

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

- -
-
->>> from pyasn1.type import univ, namedval
->>> class BitMask(univ.BitString):
-...   namedValues = namedval.NamedValues(
-...        ('read-flag', 0),
-...        ('write-flag', 2),
-...        ('run-flag', 4)
-... )
->>> bitMask = BitMask('read-flag,run-flag')
->>> bitMask
-BitMask("'10001'B")
->>> tuple(bitMask)
-(1, 0, 0, 0, 1)
->>> bitMask[4]
-1
->>>
-
-
- -

-The BitString objects mimic the properties of Python tuple type in part -of immutable sequence object protocol support. -

- - -

-1.1.7 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. -

- -
-
-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. -

- -
-
-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 OctetString objects. To avoid -possible collisions, quoted text is the default initialization syntax. -

- -
-
->>> 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. -

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

- -
-
->>> 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. -

- -
-
->>> octetString = univ.OctetString('ABCDEF')
->>> octetString.asNumbers()
-(65, 66, 67, 68, 69, 70)
->>> octetString.asOctets()
-b'ABCDEF'
-
-
- - -

-1.1.8 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. -

- -
-
-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. -

- -
-
->>> 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. -

- -
-
->>> 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. -

- - -

-1.1.9 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. -

- -
-
-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: -

- -
-
->>> 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 following types came to ASN.1 from ISO standards on character sets. -

- -
-
->>> 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: UniversalString, BMPString, UTF8String. -

- -
-
->>> 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. -

- - -

-1.1.10 Useful types -

- -

-There are three so-called useful types defined in the standard: -ObjectDescriptor, GeneralizedTime, UTCTime. They all are subtypes -of GraphicString or VisibleString types therefore useful types are -character string types. -

- -

-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. -

- -
-
->>> 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. -

- -
-
-;; 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"
-
-
- -
-
->>> 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. -

- - -

-1.2 Tagging -

- -

-In order to continue with the Constructed ASN.1 types, we will first have -to introduce the concept of tagging (and its pyasn1 implementation), as -some of the Constructed types rely upon the tagging feature. -

- -

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

- -
-
-MyIntegerType ::= [12] INTEGER
-MyOctetString ::= [APPLICATION 0] OCTET STRING
-
-
- -

-In pyasn1, tags are implemented as immutable, tuple-like objects: -

- -
-
->>> 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. -

- -
-
-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. -

- -
-
->>> from pyasn1.type import tag
->>> tagSet = tag.TagSet(
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10), # base tag
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)  # effective tag
-... )
->>> 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 (accessible through the getBaseTag() -method) is specific to pyasn1 -- the base tag is used to identify the original -ASN.1 type of an object in question. Base tag is never occurs in encoding -and is mostly used internally by pyasn1 for choosing type-specific data -processing algorithms. The "effective tag" is the one that always appears in -encoding and is used on tagSets comparation. -

- -

-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. -

- -
-
->>> from pyasn1.type import tag
->>> tagSet1 = tag.TagSet(
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) # base tag
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10) # effective tag
-... )
->>> 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: -

- -
-
-MyIntegerType ::= [12] EXPLICIT INTEGER
-
-
- -

-could be expressed in pyasn1 like this: -

- -
-
->>> from pyasn1.type import univ, tag
->>> class MyIntegerType(univ.Integer):
-...   tagSet = univ.Integer.tagSet.tagExplicitly(
-...        tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12)
-...        )
->>> myInteger = MyIntegerType(12345)
->>> myInteger.getTagSet()
-TagSet(Tag(tagClass=0, tagFormat=0, tagId=2), 
-       Tag(tagClass=128, tagFormat=32, tagId=12))
->>>
-
-
- -

-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. -

- - - -

-1.3 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. -

- - -

-1.3.1 Sequence and Set types -

- -

-The Sequence and Set types have many similar properties: -

-
    -
  • they 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, Sequence type guarantees the ordering of Sequence value components -to match their declaration order. By contrast, components of the -Set type can be ordered to best suite application's needs. -

- -
-
-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. -

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

- -
-
->>> record = Record()
->>> record.setComponentByName('id', 123)
->>> print(record.prettyPrint())
-Record:
- id=123
->>> 
->>> record.setComponentByPosition(1, 321)
->>> print(record.prettyPrint())
-Record:
- id=123
- room=321
->>>
->>> record.setDefaultComponents()
->>> print(record.prettyPrint())
-Record:
- id=123
- room=321
- house=0
-
-
- -

-Inner components of pyasn1 Sequence/Set objects could be accessed using the -following methods: -

- -
-
->>> record.getComponentByName('id')
-Integer(123)
->>> record.getComponentByPosition(1)
-Integer(321)
->>> record[2]
-Integer(0)
->>> for idx in range(len(record)):
-...   print(record.getNameByPosition(idx), record.getComponentByPosition(idx))
-id 123
-room 321
-house 0
->>>
-
-
- -

-The Set type share all the properties of Sequence type, and additionally -support by-tag component addressing (as all Set components have distinct -types). -

- -
-
->>> from pyasn1.type import univ, namedtype, tag
->>> class Gamer(univ.Set):
-...   componentType = namedtype.NamedTypes(
-...     namedtype.NamedType('score', univ.Integer()),
-...     namedtype.NamedType('player', univ.OctetString()),
-...     namedtype.NamedType('id', univ.ObjectIdentifier())
-...   )
->>> gamer = Gamer()
->>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343)
->>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal')
->>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2))
->>> print(gamer.prettyPrint())
-Gamer:
- score=121343
- player=b'Pascal'
- id=1.3.7.2
->>>
-
-
- - -

-1.3.2 SequenceOf and SetOf types -

- -

-Both, SequenceOf and SetOf types resemble an unlimited size list of components. -All the components must be of the same type. -

- -
-
-Progression ::= SEQUENCE OF INTEGER
-
-arithmeticProgression Progression ::= { 1, 3, 5, 7 }
-
-
- -

-SequenceOf and SetOf types are expressed by the very similar pyasn1 type -objects. Their components can only be addressed by position and they -both have a property of automatic resize. -

- -

-To specify inner component type, the componentType class attribute -should refer to another pyasn1 type object. -

- -
-
->>> from pyasn1.type import univ
->>> class Progression(univ.SequenceOf):
-...   componentType = univ.Integer()
->>> arithmeticProgression = Progression()
->>> arithmeticProgression.setComponentByPosition(1, 111)
->>> print(arithmeticProgression.prettyPrint())
-Progression:
--empty- 111
->>> arithmeticProgression.setComponentByPosition(0, 100)
->>> print(arithmeticProgression.prettyPrint())
-Progression:
-100 111
->>>
->>> for idx in range(len(arithmeticProgression)):
-...    arithmeticProgression.getComponentByPosition(idx)
-Integer(100)
-Integer(111)
->>>
-
-
- -

-Any scalar or constructed pyasn1 type object can serve as an inner component. -Missing components are prohibited in SequenceOf/SetOf value objects. -

- - -

-1.3.3 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. -

- -
-
-CodeOrMessage ::= CHOICE {
-  code    INTEGER,
-  message OCTET STRING
-}
-
-
- -

-In pyasn1 implementation, Choice object behaves like Set but accepts only -a single inner component at a time. It also offers a few additional methods -specific to its behaviour. -

- -
-
->>> from pyasn1.type import univ, namedtype
->>> class CodeOrMessage(univ.Choice):
-...   componentType = namedtype.NamedTypes(
-...     namedtype.NamedType('code', univ.Integer()),
-...     namedtype.NamedType('message', univ.OctetString())
-...   )
->>>
->>> codeOrMessage = CodeOrMessage()
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
->>> codeOrMessage.setComponentByName('code', 123)
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
- code=123
->>> codeOrMessage.setComponentByName('message', 'my string value')
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
- message=b'my string value'
->>>
-
-
- -

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

- -
-
->>> codeOrMessage.getName()
-'message'
->>> codeOrMessage.getComponent()
-OctetString(b'my string value')
->>>
-
-
- - -

-1.3.4 Any type -

- -

-The ASN.1 ANY type is a kind of wildcard or placeholder that matches -any other type without knowing it in advance. Like CHOICE type, ANY -has no base tag. -

- -
-
-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 Any value object share the properties of -pyasn1 OctetString object. -

- -
-
->>> 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. -

- - -

-1.4 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. -

- - -

-1.4.1 Single value constraint -

- -

-This kind of constraint allows for limiting type to a finite, specified set -of values. -

- -
-
-DialButton ::= OCTET STRING (
-  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
-)
-
-
- -

-Its pyasn1 implementation would look like: -

- -
-
->>> from pyasn1.type import constraint
->>> c = constraint.SingleValueConstraint(
-  '0','1','2','3','4','5','6','7','8','9'
-)
->>> c
-SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
->>> c('0')
->>> c('A')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError: 
-  SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
->>> 
-
-
- -

-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. -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class DialButton(univ.OctetString):
-...   subtypeSpec = constraint.SingleValueConstraint(
-...       '0','1','2','3','4','5','6','7','8','9'
-...   )
->>> DialButton('0')
-DialButton(b'0')
->>> DialButton('A')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
->>> 
-
-
- -

-Constrained pyasn1 value object can never hold a violating value. -

- - -

-1.4.2 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. -

- -
-
-Teenagers ::= INTEGER (13..19)
-
-
- -

-And in pyasn1 terms: -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class Teenagers(univ.Integer):
-...   subtypeSpec = constraint.ValueRangeConstraint(13, 19)
->>> Teenagers(14)
-Teenagers(14)
->>> Teenagers(20)
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ValueRangeConstraint(13, 19) failed at: 20
->>> 
-
-
- -

-Value range constraint usually applies numeric types. -

- - -

-1.4.3 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. -

- -
-
-TwoBits ::= BIT STRING (SIZE (2))
-
-
- -

-Express the same grammar in pyasn1: -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class TwoBits(univ.BitString):
-...   subtypeSpec = constraint.ValueSizeConstraint(2, 2)
->>> TwoBits((1,1))
-TwoBits("'11'B")
->>> TwoBits((1,1,0))
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ValueSizeConstraint(2, 2) failed at: (1, 1, 0)
->>> 
-
-
- -

-Size constraint can be applied to potentially massive values - bit or octet -strings, SEQUENCE OF/SET OF values. -

- - -

-1.4.4 Alphabet constraint -

- -

-The permitted alphabet constraint is similar to Single value constraint -but constraint applies to individual characters of a value. -

- -
-
-MorseCode ::= PrintableString (FROM ("."|"-"|" "))
-
-
- -

-And in pyasn1: -

- -
-
->>> from pyasn1.type import char, constraint
->>> class MorseCode(char.PrintableString):
-...   subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ")
->>> MorseCode("...---...")
-MorseCode('...---...')
->>> MorseCode("?")
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  PermittedAlphabetConstraint(".", "-", " ") failed at: "?"
->>> 
-
-
- -

-Current implementation does not handle ranges of characters in constraint -(FROM "A".."Z" syntax), one has to list the whole set in a range. -

- - -

-1.4.5 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: -

- -
-
-PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11)
-
-
- -

-Constraint intersection object serves the logic above: -

- -
-
->>> from pyasn1.type import char, constraint
->>> class PhoneNumber(char.NumericString):
-...   subtypeSpec = constraint.ConstraintsIntersection(
-...     constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
-...     constraint.ValueSizeConstraint(11, 11)
-...   )
->>> PhoneNumber('79039343212')
-PhoneNumber('79039343212')
->>> PhoneNumber('?9039343212')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsIntersection(
-    PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
-      ValueSizeConstraint(11, 11)) failed at: 
-   PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212"
->>> PhoneNumber('9343212')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsIntersection(
-    PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'),
-      ValueSizeConstraint(11, 11)) failed at:
-  ValueSizeConstraint(10, 10) failed at: "9343212"
->>>
-
-
- -

-Union of constraints works by making sure that a value is compliant -to any of the constraint in a set. For instance: -

- -
-
-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: -

- -
-
->>> from pyasn1.type import char, constraint
->>> class CapitalOrSmall(char.IA5String):
-...   subtypeSpec = constraint.ConstraintsUnion(
-...     constraint.PermittedAlphabetConstraint('A','B','C'),
-...     constraint.PermittedAlphabetConstraint('a','b','c')
-...   )
->>> CapitalOrSmall('ABBA')
-CapitalOrSmall('ABBA')
->>> CapitalOrSmall('abba')
-CapitalOrSmall('abba')
->>> CapitalOrSmall('Abba')
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'),
-    PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba"
->>>
-
-
- -

-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. -

- -
-
-NoZero ::= INTEGER (ALL EXCEPT 0)
-
-
- -

-In pyasn1 the above definition would read: -

- -
-
->>> from pyasn1.type import univ, constraint
->>> class NoZero(univ.Integer):
-...   subtypeSpec = constraint.ConstraintsExclusion(
-...     constraint.SingleValueConstraint(0)
-...   )
->>> NoZero(1)
-NoZero(1)
->>> NoZero(0)
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0
->>>
-
-
- -

-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. -

- - -

-1.5 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): -

- -
-
->>> 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. -

- - -

-2. Codecs -

- -

-In ASN.1 context, -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 -. -

- -

-As of this writing, codecs implemented in pyasn1 are all stateless, mostly -to keep the code simple. -

- -

-The pyasn1 package currently supports -BER codec and -its variations -- -CER and -DER. -More ASN.1 codecs are planned for implementation in the future. -

- - -

-2.1 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: -

- -
-
->>> 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. -

- -
-
->>> 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. -

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

-2.2 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. -

- -
-
->>> 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. -

- -
-
->>> 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 handbook, when an ASN.1 type is implicitly -tagged, previous outermost tag is lost and never appears in substrate. -If it is the base tag that gets lost, decoder is unable to pick type-specific -value decoder at its table of built-in types, and therefore recover -the value part, based only on the information contained in substrate. The -approach taken by pyasn1 decoder is to use a prototype pyasn1 type object (or -a set of them) to 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 paper). -

- -
-
->>> 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: -

- -
-
->>> 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. -

- -
-
->>> from pyasn1.type import univ, constraint
->>> from pyasn1.codec.ber import encoder, decoder
->>> class DialDigit(univ.Integer):
-...   subtypeSpec = constraint.ValueRangeConstraint(0,9)
->>> substrate = encoder.encode(univ.Integer(13))
->>> decoder.decode(substrate)
-(Integer(13), b'')
->>> decoder.decode(substrate, asn1Spec=DialDigit())
-Traceback (most recent call last):
-...
-pyasn1.type.error.ValueConstraintError:
-  ValueRangeConstraint(0, 9) failed at: 13
->>> 
-
-
- -

-Similarily to encoders, to use CER or DER decoders application has to -explicitly import and call them - all APIs are compatible. -

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

-2.2.1 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: -

- -
-
->>> from pyasn1.type import univ, namedtype
->>> class CodeOrMessage(univ.Choice):
-...   componentType = namedtype.NamedTypes(
-...     namedtype.NamedType('code', univ.Integer()),
-...     namedtype.NamedType('message', univ.OctetString())
-...   )
->>>
->>> codeOrMessage = CodeOrMessage()
->>> codeOrMessage.setComponentByName('message', 'my string value')
->>> print(codeOrMessage.prettyPrint())
-CodeOrMessage:
- message=b'my string value'
->>>
-
-
- -

-Let's now encode this Choice object and then decode its substrate -with and without pyasn1 specification object: -

- -
-
->>> 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 paper, 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. -

- -
-
->>> 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: -

- -
-
->>> 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 for more information. -

- - -

-2.2.2 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. -

- -
-
->>> 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. -

- - -

-3. Feedback and getting help -

- -

-Although pyasn1 software is almost a decade old and used in many production -environments, it still may have bugs and non-implemented pieces. Anyone -who happens to run into such defect is welcome to complain to -pyasn1 mailing list -or better yet fix the issue and send -me the patch. -

- -

-Typically, pyasn1 is used for building arbitrary protocol support into -various applications. This involves manual translation of ASN.1 data -structures into their pyasn1 implementations. To save time and effort, -data structures for some of the popular protocols are pre-programmed -and kept for further re-use in form of the - -pyasn1-modules package. For instance, many structures for PKI (X.509, -PKCS#*, CRMF, OCSP), LDAP and SNMP are present. -Applications authors are advised to import and use relevant modules -from that package whenever needed protocol structures are already -there. New protocol modules contributions are welcome. -

- -

-And finally, the latest pyasn1 package revision is available for free -download from -project home and -also from the -Python package repository. -

- -
- -
-
- - diff --git a/third_party/python/pyasn1/doc/scalar.html b/third_party/python/pyasn1/doc/scalar.html deleted file mode 100644 index e5ccefe60e31..000000000000 --- a/third_party/python/pyasn1/doc/scalar.html +++ /dev/null @@ -1,794 +0,0 @@ - - -PyASN1 data model and scalar types - - - - -
- - - - -
- -

-1. 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. -

- -
-
->>> 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: -

- -
-
->>> from pyasn1.type import univ
->>> asn1IntegerType = univ.Integer()
->>> asn1IntegerType - 2
-...
-pyasn1.error.PyAsn1Error: No value for __coerce__()
-
-
- - -

-1.1 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. -

- - -

-1.1.1 Boolean type -

- -

-This is the simplest type those values could be either True or False. -

- -
-
-;; type specification
-FunFactorPresent ::= BOOLEAN
-
-;; values declaration and assignment
-pythonFunFactor FunFactorPresent ::= TRUE
-cobolFunFactor FunFactorPresent :: FALSE
-
-
- -

-And here's pyasn1 version of it: -

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

-1.1.2 Null type -

- -

-The NULL type is sometimes used to express the absense of any information. -

- -
-
-;; type specification
-Vote ::= CHOICE {
-  agreed BOOLEAN,
-  skip NULL
-}
-
- -;; value declaration and assignment -myVote Vote ::= skip:NULL - - -

-We will explain the CHOICE type later in this paper, meanwhile the NULL -type: -

- -
-
->>> from pyasn1.type import univ
->>> skip = univ.Null()
->>> skip
-Null('')
->>>
-
-
- - -

-1.1.3 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. -

- -
-
-;; values specification
-age-of-universe INTEGER ::= 13750000000
-mean-martian-surface-temperature INTEGER ::= -63
-
-
- -

-A rather strigntforward mapping into pyasn1: -

- -
-
->>> 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. -

- -
-
-Temperature ::= INTEGER {
-  freezing(0),
-  boiling(100) 
-}
-
-
- -

-The Temperature type expressed in pyasn1: -

- -
-
->>> 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 this paper). -

- - -

-1.1.4 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. -

- -
-
-error-status ::= ENUMERATED {
-  no-error(0),
-  authentication-error(10),
-  authorization-error(20),
-  general-failure(51)
-}
-
-
- -

-When constructing Enumerated type we will use two pyasn1 features: values -labels (as mentioned above) and value constraint (will be described in -more details later on). -

- -
-
->>> 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. -

- - -

-1.1.5 Real type -

- -

-Values of the Real type are a three-component tuple of mantissa, base and -exponent. All three are integers. -

- -
-
-pi ::= REAL { mantissa 314159, base 10, exponent -5 }
-
-
- -

-Corresponding pyasn1 objects can be initialized with either a three-component -tuple or a Python float. Infinite values could be expressed in a way, -compatible with Python float type. - -

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

- - -

-1.1.6 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. -

- -
-
-public-key BIT STRING ::= '1010111011110001010110101101101
-                           1011000101010000010110101100010
-                           0110101010000111101010111111110'B
-
-signature  BIT STRING ::= 'AF01330CD932093392100B39FF00DE0'H
-
-
- -

-The pyasn1 BitString objects can initialize from native ASN.1 notation -(base 2 or base 16 strings) or from a Python tuple of binary components. -

- -
-
->>> from pyasn1.type import univ
->>> publicKey = univ.BitString(
-...          "'1010111011110001010110101101101"
-...          "1011000101010000010110101100010"
-...          "0110101010000111101010111111110'B"
-)
->>> publicKey
-BitString("'10101110111100010101101011011011011000101010000010110101100010\
-0110101010000111101010111111110'B")
->>> signature = univ.BitString(
-...          "'AF01330CD932093392100B39FF00DE0'H"
-... )
->>> signature
-BitString("'101011110000000100110011000011001101100100110010000010010011001\
-1100100100001000000001011001110011111111100000000110111100000'B")
->>> fingerprint = univ.BitString(
-...          (1, 0, 1, 1 ,0, 1, 1, 1, 0, 1, 0, 1)
-... )
->>> fingerprint
-BitString("'101101110101'B")
->>>
-
-
- -

-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. -

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

- -
-
->>> from pyasn1.type import univ, namedval
->>> class BitMask(univ.BitString):
-...   namedValues = namedval.NamedValues(
-...        ('read-flag', 0),
-...        ('write-flag', 2),
-...        ('run-flag', 4)
-... )
->>> bitMask = BitMask('read-flag,run-flag')
->>> bitMask
-BitMask("'10001'B")
->>> tuple(bitMask)
-(1, 0, 0, 0, 1)
->>> bitMask[4]
-1
->>>
-
-
- -

-The BitString objects mimic the properties of Python tuple type in part -of immutable sequence object protocol support. -

- - -

-1.1.7 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. -

- -
-
-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. -

- -
-
-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 OctetString objects. To avoid -possible collisions, quoted text is the default initialization syntax. -

- -
-
->>> 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. -

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

- -
-
->>> 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. -

- -
-
->>> octetString = univ.OctetString('ABCDEF')
->>> octetString.asNumbers()
-(65, 66, 67, 68, 69, 70)
->>> octetString.asOctets()
-b'ABCDEF'
-
-
- - -

-1.1.8 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. -

- -
-
-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. -

- -
-
->>> 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. -

- -
-
->>> 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. -

- - -

-1.1.9 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. -

- -
-
-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: -

- -
-
->>> 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 following types came to ASN.1 from ISO standards on character sets. -

- -
-
->>> 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: UniversalString, BMPString, UTF8String. -

- -
-
->>> 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. -

- - -

-1.1.10 Useful types -

- -

-There are three so-called useful types defined in the standard: -ObjectDescriptor, GeneralizedTime, UTCTime. They all are subtypes -of GraphicString or VisibleString types therefore useful types are -character string types. -

- -

-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. -

- -
-
->>> 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. -

- -
-
-;; 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"
-
-
- -
-
->>> 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. -

- -
- -
-
- - diff --git a/third_party/python/pyasn1/doc/source/changelog.rst b/third_party/python/pyasn1/doc/source/changelog.rst new file mode 100644 index 000000000000..095fc83a61c5 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/changelog.rst @@ -0,0 +1,6 @@ + +Changelog +========= + +.. include:: ../../CHANGES.rst + diff --git a/third_party/python/pyasn1/doc/source/conf.py b/third_party/python/pyasn1/doc/source/conf.py new file mode 100644 index 000000000000..258e74bde54e --- /dev/null +++ b/third_party/python/pyasn1/doc/source/conf.py @@ -0,0 +1,323 @@ +# -*- coding: utf-8 -*- +# +# PyASN1 documentation build configuration file, created by +# sphinx-quickstart on Sat Jun 27 23:15:54 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +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 +# documentation root, use os.path.abspath to make it absolute, like shown here. +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['.templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'contents' + +# General information about the project. +project = u'PyASN1' +# noinspection PyShadowingBuiltins +copyright = u'2005-2017, Ilya Etingof ' +author = u'Ilya Etingof ' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.3' +# The full version, including alpha/beta/rc tags. +release = '0.3.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None +html_title = "PyASN1" + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = "" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +if 'PYASN1DEV' in os.environ: + html_static_path = ['.static'] + +# Custom CSS theme +if 'PYASN1DEV' in os.environ: + html_style = 'css/rtdimproved.css' + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pyasn1doc' + +html_context = { + 'include_analytics': 'PYASN1DEV' in os.environ +} + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # 'preamble': '', + + # Latex figure (float) alignment + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'PyASN1.tex', u'PyASN1 Documentation', + u'Ilya Etingof \\textless{}etingof@gmail.com\\textgreater{}', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pyasn1', u'PyASN1 Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'PyASN1', u'PyASN1 Documentation', + author, 'PyASN1', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'python': ('https://docs.python.org/3.4/', None)} + +# this merges constructor docstring with class docstring +autoclass_content = 'both' +# Sort members by type +autodoc_member_order = 'bysource' +# autodoc_member_order = 'groupwise' + +# Napoleon settings +napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = False +napoleon_use_rtype = False diff --git a/third_party/python/pyasn1/doc/source/contents.rst b/third_party/python/pyasn1/doc/source/contents.rst new file mode 100644 index 000000000000..66d25072be56 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/contents.rst @@ -0,0 +1,194 @@ + +ASN.1 library for Python +======================== + +.. toctree:: + :maxdepth: 2 + +Abstract Syntax Notation One (`ASN.1 +`_) is a +technology for exchanging structured data in a universally understood, +hardware agnostic way. Many industrial, security and telephony +applications heavily rely on ASN.1. + +The `pyasn1 `_ library implements +ASN.1 support in pure-Python. + +What is ASN.1 +------------- + +ASN.1 is a large, arguably over-engineered and extremely old data modelling and +serialization tool. It is probably among the first serialization protocols in +the history of computer science and technology. + +ASN.1 started its life over 30 years ago as a serialization mechanism for the first +electronic mail (known as X.400). Later on if was split off the e-mail application +and become a stand-alone tech still being actively supported by its designers +and widely used in industry and technology. + +Since then ASN.1 is sort of haunted by its relations with the OSI model -- the +first, unsuccessful, version of the Internet. You can read many interesting +`discussions `_ on that topic. + +In the following years, generations of software engineers tackled the serialization +problem many times. We can see that in Google's `ProtoBuffers `_ +or `FlatBuffers `_, for example. +Interestingly, many new takes on binary protocol design do not depart +far from ASN.1 from technical perspective. It's more of a matter of striking +a balance between processing overhead, wire format overhead and human +readability. + +Looking at what ASN.1 has to offer, it has three loosely coupled parts: + +* Data types: the standard introduces a collection of basic data types + (integers, bits, strings, arrays and records) that can be used for describing + arbitrarily complex, nested data structures. + +* Serialization protocols: the above data structures could be converted into a + series of octets for storage or transmission over the wire as well as + recovered back into their structured form. The system is fully agnostic + to hardware architectures differences. + +* Schema language: ASN.1 data structures could be described in terms + of a schema language for ASN.1 compiler to turn it into platform-specific + implementation. + +ASN.1 applications +------------------ + +Being an old and generally successful standard, ASN.1 is widely +adopted for many uses. To give you an example, these technologies +use ASN.1 for their data exchange needs: + +* Signaling standards for the public switched telephone network (SS7 family) +* Network management standards (SNMP, CMIP) +* Directory standards (X.500 family, LDAP) +* Public Key Infrastructure standards (X.509, etc.) +* PBX control (CSTA) +* IP-based Videoconferencing (H.323 family) +* Biometrics (BIP, CBEFF, ACBio) +* Intelligent transportation (SAE J2735) +* Cellular telephony (GSM, GPRS/EDGE, UMTS, LTE) + +ASN.1 gotchas +------------- + +Apparently, ASN.1 is hard to implement properly. Quality open-source +ASN.1 tools are rare, but ad-hoc implementations are numerous. Judging from the +`statistics `_ on discovered +security vulnerabilities, many people have implemented ASN.1 parsers +and oftentimes fell victim to its edge cases. + +On the bright side, ASN.1 has been around for a long time, it is well understood +and security reviewed. + +Library capabilities +-------------------- + +As of this moment, pyasn1 library implements all ASN.1 data +types as Python objects in accordance with X.208 standard. Later, +post-1995, revision (X.680) introduced some changes to the schema +language which may not be fully supported by pyasn1. Aside from data +types a collection of data transformation codecs comes with pyasn1 package. + +As for ASN.1 schema language, pyasn1 package does +not ship any compiler for it. However, there's a tool called +`asn1late `_ which is an ASN.1 +grammar parser paired to code generator capable of generating pyasn1 +code. So this is an alternative (or at least a good start) to manual +implementation of pyasn1 classes from ASN.1 specification. + +Both `pyasn1 `_ and +`pyasn1-modules `_ libraries +can be used out-of-the-box with Python versions 2.4 through 3.6. +No external dependencies required. + +Documentation +------------- + +.. toctree:: + :maxdepth: 2 + + /docs/tutorial + /docs/api-reference + +Use case +-------- + + .. toctree:: + :maxdepth: 2 + + /example-use-case + +Download & Install +------------------ + +The PyASN1 software is provided under terms and conditions of BSD-style +:ref:`license`, and can be freely downloaded from `Github `_ +or `PyPI `_. + +It is pure-Python and has no dependencies. Considering how much industrial or finance +software can be stuck with an old platform (think RHEL 5), we struggle to maintain its +compatibility back to the very pre-historic Python (which is 2.4!). + +The best way to obtain PyASN1 is by running `pip`: + +.. code-block:: bash + + $ pip install pyasn1 + +or + +.. code-block:: bash + + $ easy_install pyasn1 + +You may also want to use `pyasn1-modules`: + +.. code-block:: bash + + $ pip install pyasn1-modules + +Changes +------- + +All changes and release history is maintained in changelog. There you +could also download the latest unreleased pyasn1 tarball containing +the latest fixes and improvements. + + .. toctree:: + :maxdepth: 1 + + /changelog + +Getting help +------------ + +Please, file your `issues `_ +and `PRs `_ at GitHub. +Alternatively, you could ask for help at +`Stack Overflow `_ +or search +`pyasn1-users `_ +mailing list archive. + +Books on ASN.1 +-------------- + +The pyasn1 implementation is largely based on reading up the following awesome +books: + +* `ASN.1 - Communication between heterogeneous systems `_ by Olivier Dubuisson +* `ASN.1 Complete `_ by Prof John Larmouth + +Here you can get the official standards which is hard to read: + +* `ITU standards `_ + +On the other end of the readability spectrum, here is a quick and sweet write up: + +* `A Layman's Guide to a Subset of ASN.1, BER, and DER `_ by Burton S. Kaliski + +If you are working with ASN.1, we'd highly recommend reading a proper +book on the subject. + diff --git a/third_party/python/pyasn1/doc/source/docs/api-reference.rst b/third_party/python/pyasn1/doc/source/docs/api-reference.rst new file mode 100644 index 000000000000..0f98527b0323 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/api-reference.rst @@ -0,0 +1,30 @@ + +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/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/third_party/python/pyasn1/doc/source/docs/codec/ber/contents.rst b/third_party/python/pyasn1/doc/source/docs/codec/ber/contents.rst new file mode 100644 index 000000000000..9f15a94111a8 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/codec/ber/contents.rst @@ -0,0 +1,7 @@ + +Basic Encoding Rules +-------------------- + +.. autofunction:: pyasn1.codec.ber.encoder.encode(value, defMode=True, maxChunkSize=0) + +.. autofunction:: pyasn1.codec.ber.decoder.decode(substrate, asn1Spec=None) diff --git a/third_party/python/pyasn1/doc/source/docs/codec/cer/contents.rst b/third_party/python/pyasn1/doc/source/docs/codec/cer/contents.rst new file mode 100644 index 000000000000..58b46daa9120 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/codec/cer/contents.rst @@ -0,0 +1,7 @@ + +Canonical Encoding Rules +------------------------ + +.. autofunction:: pyasn1.codec.cer.encoder.encode(value) + +.. autofunction:: pyasn1.codec.cer.decoder.decode(substrate, asn1Spec=None) diff --git a/third_party/python/pyasn1/doc/source/docs/codec/der/contents.rst b/third_party/python/pyasn1/doc/source/docs/codec/der/contents.rst new file mode 100644 index 000000000000..dddee8ecd561 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/codec/der/contents.rst @@ -0,0 +1,7 @@ + +Distinguished Encoding Rules +---------------------------- + +.. autofunction:: pyasn1.codec.der.encoder.encode(value) + +.. autofunction:: pyasn1.codec.der.decoder.decode(substrate, asn1Spec=None) diff --git a/third_party/python/pyasn1/doc/source/docs/codec/native/contents.rst b/third_party/python/pyasn1/doc/source/docs/codec/native/contents.rst new file mode 100644 index 000000000000..11e96f00716b --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/codec/native/contents.rst @@ -0,0 +1,7 @@ + +Native Python types +------------------- + +.. autofunction:: pyasn1.codec.native.encoder.encode(asn1Value) + +.. autofunction:: pyasn1.codec.native.decoder.decode(pyObject, asn1Spec) diff --git a/third_party/python/pyasn1/doc/source/docs/tutorial.rst b/third_party/python/pyasn1/doc/source/docs/tutorial.rst new file mode 100644 index 000000000000..c072a6be3d2d --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/tutorial.rst @@ -0,0 +1,1778 @@ + +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 `_ +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 +`_ . + +As of this writing, codecs implemented in pyasn1 are all stateless, +mostly to keep the code simple. + +The pyasn1 package currently supports +`BER `_ codec and +its variations -- +`CER `_ and +`DER `_. +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 +`_ +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/third_party/python/pyasn1/doc/source/docs/type/char/bmpstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/bmpstring.rst new file mode 100644 index 000000000000..3809e9b609d8 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/bmpstring.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: BMPString + +.. |encoding| replace:: utf-16-be + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.BMPString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialized into UTF-16 big endian. + + .. automethod:: pyasn1.type.char.BMPString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.BMPString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/contents.rst b/third_party/python/pyasn1/doc/source/docs/type/char/contents.rst new file mode 100644 index 000000000000..ec01d93b559b --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/contents.rst @@ -0,0 +1,20 @@ + +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/third_party/python/pyasn1/doc/source/docs/type/char/generalstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/generalstring.rst new file mode 100644 index 000000000000..8ce730ff53c4 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/generalstring.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: GeneralString + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.GeneralString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a character string similar to :py:class:`GraphicString` but additionally + including control characters. + + .. automethod:: pyasn1.type.char.GeneralString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.GeneralString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/graphicstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/graphicstring.rst new file mode 100644 index 000000000000..1f5720922b17 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/graphicstring.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: GraphicString + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.GraphicString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a character string that can hold any "graphical" characters + mixed with control ones to select particular alphabet. + + .. automethod:: pyasn1.type.char.GraphicString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.GraphicString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/ia5string.rst b/third_party/python/pyasn1/doc/source/docs/type/char/ia5string.rst new file mode 100644 index 000000000000..1ae80af1acb5 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/ia5string.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: IA5String + +.. |encoding| replace:: us-ascii + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.IA5String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a basic character string first published in 1963 as an ISO/ITU standard, then it turned into ASCII. + + .. automethod:: pyasn1.type.char.IA5String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.IA5String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/iso646string.rst b/third_party/python/pyasn1/doc/source/docs/type/char/iso646string.rst new file mode 100644 index 000000000000..f21836ab19af --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/iso646string.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: ISO646String + +.. |encoding| replace:: us-ascii + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.ISO646String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type is an alias to the :py:class:`VisibleString` type + + .. automethod:: pyasn1.type.char.ISO646String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.ISO646String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/numericstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/numericstring.rst new file mode 100644 index 000000000000..dc805e4d3ee8 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/numericstring.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: NumericString + +.. |encoding| replace:: us-ascii + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.NumericString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| models character string that can be entered from a telephone handset. + + .. automethod:: pyasn1.type.char.NumericString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.NumericString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/printablestring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/printablestring.rst new file mode 100644 index 000000000000..22ebe2896f61 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/printablestring.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: PrintableString + +.. |encoding| replace:: us-ascii + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.PrintableString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| models character string that can be entered from a very rudimentary terminals featuring letters, + digits and punctuation marks. + + .. automethod:: pyasn1.type.char.PrintableString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.PrintableString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/t61string.rst b/third_party/python/pyasn1/doc/source/docs/type/char/t61string.rst new file mode 100644 index 000000000000..ed9d61ee17fe --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/t61string.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: T61String + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.T61String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type is an alias to :py:class:`TeletexString` type. + + .. automethod:: pyasn1.type.char.T61String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.T61String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/teletexstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/teletexstring.rst new file mode 100644 index 000000000000..86aa248c5192 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/teletexstring.rst @@ -0,0 +1,19 @@ + +.. |ASN.1| replace:: TeletexString + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.TeletexString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models character string that can be entered from a sophisticated text processing machines + (by 20-th century standards) featuring letters from multiple alphabets (308 characters!), digits, + punctuation marks and escape sequences. + + .. automethod:: pyasn1.type.char.TeletexString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.TeletexString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/universalstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/universalstring.rst new file mode 100644 index 000000000000..e3159dc4a47f --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/universalstring.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: UniversalString + +.. |encoding| replace:: utf-32-be + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.UniversalString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialized into UTF-32 big endian. + + .. automethod:: pyasn1.type.char.UniversalString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.UniversalString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/utf8string.rst b/third_party/python/pyasn1/doc/source/docs/type/char/utf8string.rst new file mode 100644 index 000000000000..ddeeebf0782c --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/utf8string.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: UTF8String + +.. |encoding| replace:: utf-8 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.UTF8String(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialized into UTF-8. + + .. automethod:: pyasn1.type.char.UTF8String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.UTF8String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/videotexstring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/videotexstring.rst new file mode 100644 index 000000000000..0570471595ee --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/videotexstring.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: VideotexString + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.VideotexString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models character string that can be consumed by sophisticated video + terminals (by 20-th century standards) to render ascii-art style pictures and animations. + + .. automethod:: pyasn1.type.char.VideotexString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.VideotexString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/char/visiblestring.rst b/third_party/python/pyasn1/doc/source/docs/type/char/visiblestring.rst new file mode 100644 index 000000000000..b895eb5252cd --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/char/visiblestring.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: VisibleString + +.. |encoding| replace:: us-ascii + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.char.VisibleString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap + + .. note:: + + The |ASN.1| type models a character string that can hold any "graphical" characters + mixed with control ones to select particular alphabet. + + .. automethod:: pyasn1.type.char.VisibleString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.char.VisibleString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/namedtype/contents.rst b/third_party/python/pyasn1/doc/source/docs/type/namedtype/contents.rst new file mode 100644 index 000000000000..57bdc5cd4042 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedtype/contents.rst @@ -0,0 +1,11 @@ + +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/third_party/python/pyasn1/doc/source/docs/type/namedtype/defaultednamedtype.rst b/third_party/python/pyasn1/doc/source/docs/type/namedtype/defaultednamedtype.rst new file mode 100644 index 000000000000..9a331dc67c20 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedtype/defaultednamedtype.rst @@ -0,0 +1,12 @@ + +.. |NamedType| replace:: DefaultedNamedType + +|NamedType| +------------------ + +.. autoclass:: pyasn1.type.namedtype.DefaultedNamedType + :members: + + .. note:: + + The |NamedType| class models named field of a constructed ASN.1 type which has a default value. diff --git a/third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtype.rst b/third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtype.rst new file mode 100644 index 000000000000..ea978efb8bad --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtype.rst @@ -0,0 +1,12 @@ + +.. |NamedType| replace:: NamedType + +|NamedType| +----------- + +.. autoclass:: pyasn1.type.namedtype.NamedType + :members: + + .. note:: + + The |NamedType| class models a mandatory field of a constructed ASN.1 type. diff --git a/third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtypes.rst b/third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtypes.rst new file mode 100644 index 000000000000..fa8234d527c5 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedtype/namedtypes.rst @@ -0,0 +1,6 @@ + +NamedTypes +---------- + +.. autoclass:: pyasn1.type.namedtype.NamedTypes + :members: diff --git a/third_party/python/pyasn1/doc/source/docs/type/namedtype/optionalnamedtype.rst b/third_party/python/pyasn1/doc/source/docs/type/namedtype/optionalnamedtype.rst new file mode 100644 index 000000000000..8655a1e9d77b --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedtype/optionalnamedtype.rst @@ -0,0 +1,12 @@ + +.. |NamedType| replace:: OptionalNamedType + +|NamedType| +------------------ + +.. autoclass:: pyasn1.type.namedtype.OptionalNamedType + :members: + + .. note:: + + The |NamedType| class models an optional field of a constructed ASN.1 type. diff --git a/third_party/python/pyasn1/doc/source/docs/type/namedval/contents.rst b/third_party/python/pyasn1/doc/source/docs/type/namedval/contents.rst new file mode 100644 index 000000000000..3e5e8302a78c --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedval/contents.rst @@ -0,0 +1,13 @@ + +Enumerating numbers +------------------- + +Some ASN.1 types such as :py:class:`~pyasn1.type.univ.Integer`, +:py:class:`~pyasn1.type.univ.Enumerated` and +:py:class:`~pyasn1.type.univ.BitString` may enumerate their values +with human-friendly labels. + +.. toctree:: + :maxdepth: 2 + + /docs/type/namedval/namedval diff --git a/third_party/python/pyasn1/doc/source/docs/type/namedval/namedval.rst b/third_party/python/pyasn1/doc/source/docs/type/namedval/namedval.rst new file mode 100644 index 000000000000..24847a931ca7 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/namedval/namedval.rst @@ -0,0 +1,11 @@ + +.. |NamedValues| replace:: NamedValues + +|NamedValues| +------------- + +The |NamedValues| class associates human-friendly names to a set of numbers +or bits. + +.. autoclass:: pyasn1.type.namedval.NamedValues + :members: diff --git a/third_party/python/pyasn1/doc/source/docs/type/tag/contents.rst b/third_party/python/pyasn1/doc/source/docs/type/tag/contents.rst new file mode 100644 index 000000000000..955412a99cb4 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/tag/contents.rst @@ -0,0 +1,10 @@ + +Tagging types +------------- + +.. toctree:: + :maxdepth: 2 + + /docs/type/tag/tag + /docs/type/tag/tagset + /docs/type/tag/tagmap diff --git a/third_party/python/pyasn1/doc/source/docs/type/tag/tag.rst b/third_party/python/pyasn1/doc/source/docs/type/tag/tag.rst new file mode 100644 index 000000000000..65be83634401 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/tag/tag.rst @@ -0,0 +1,8 @@ + +Solitary tag +------------ + +.. automodule:: pyasn1.type.tag + :members: Tag, tagClassUniversal, tagClassApplication, tagClassContext, + tagClassPrivate, tagFormatSimple, tagFormatConstructed + diff --git a/third_party/python/pyasn1/doc/source/docs/type/tag/tagmap.rst b/third_party/python/pyasn1/doc/source/docs/type/tag/tagmap.rst new file mode 100644 index 000000000000..5891abc95b87 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/tag/tagmap.rst @@ -0,0 +1,6 @@ + +Tag->type map +------------- + +.. autoclass:: pyasn1.type.tagmap.TagMap + :members: diff --git a/third_party/python/pyasn1/doc/source/docs/type/tag/tagset.rst b/third_party/python/pyasn1/doc/source/docs/type/tag/tagset.rst new file mode 100644 index 000000000000..5ffb2fc44ab7 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/tag/tagset.rst @@ -0,0 +1,6 @@ + +Composition of tags +------------------- + +.. autoclass:: pyasn1.type.tag.TagSet + :members: diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/any.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/any.rst new file mode 100644 index 000000000000..d1aef27d554c --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/any.rst @@ -0,0 +1,20 @@ + +.. |ASN.1| replace:: Any + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Any(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1', binValue=NoValue(),hexValue=NoValue()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec + + .. note:: + + The |ASN.1| type models an arbitrary value of an arbitrary type. 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. + + .. 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/third_party/python/pyasn1/doc/source/docs/type/univ/bitstring.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/bitstring.rst new file mode 100644 index 000000000000..17f61160f30f --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/bitstring.rst @@ -0,0 +1,15 @@ + +.. |ASN.1| replace:: BitString + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.BitString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues(),binValue=NoValue(), hexValue=NoValue()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, asInteger, asNumbers, asOctets, asBinary, fromHexString, fromBinaryString, fromOctetString + + .. note:: + + The |ASN.1| type models an arbitrary sequence of bits. + + .. automethod:: pyasn1.type.univ.BitString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues(),binValue=NoValue(), hexValue=NoValue()) + .. automethod:: pyasn1.type.univ.BitString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), , namedValues=NamedValues(),binValue=NoValue(), hexValue=NoValue()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/boolean.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/boolean.rst new file mode 100644 index 000000000000..c486bd04420c --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/boolean.rst @@ -0,0 +1,15 @@ + +.. |ASN.1| replace:: Boolean + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Boolean(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec + + .. note:: + + The |ASN.1| type models a BOOLEAN that can be either TRUE or FALSE. + + .. automethod:: pyasn1.type.univ.Boolean.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.Boolean.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(), subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/choice.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/choice.rst new file mode 100644 index 000000000000..1507e9d22ae8 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/choice.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: Choice + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Choice(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, + getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents, + getComponentByType, setComponentByType, getName, getComponent + + .. note:: + + The |ASN.1| type can only hold a single component at a time belonging to the list of allowed types. + + .. automethod:: pyasn1.type.univ.Choice.clone(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.Choice.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/contents.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/contents.rst new file mode 100644 index 000000000000..d0f873278aaa --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/contents.rst @@ -0,0 +1,23 @@ + +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/third_party/python/pyasn1/doc/source/docs/type/univ/enumerated.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/enumerated.rst new file mode 100644 index 000000000000..2e88e9943348 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/enumerated.rst @@ -0,0 +1,16 @@ + +.. |ASN.1| replace:: Enumerated + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Enumerated(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, namedValues + + .. note:: + + The |ASN.1| type models bounded set of named integer values. Other than that, it is identical to + the *Integer* class. + + .. automethod:: pyasn1.type.univ.Enumerated.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues()) + .. automethod:: pyasn1.type.univ.Enumerated.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/integer.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/integer.rst new file mode 100644 index 000000000000..fd9fbec6fbd0 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/integer.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: Integer + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Integer(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, + subtypeSpec, namedValues + + .. note:: + + The |ASN.1| type models an arbitrary integer. INTEGER values can be positive, negative, + or zero, and can have any magnitude. + + .. automethod:: pyasn1.type.univ.Integer.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues()) + .. automethod:: pyasn1.type.univ.Integer.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), namedValues=NamedValues()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/null.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/null.rst new file mode 100644 index 000000000000..a959146053f8 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/null.rst @@ -0,0 +1,15 @@ + +.. |ASN.1| replace:: Null + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Null(value=NoValue(), tagSet=TagSet()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec + + .. note:: + + The |ASN.1| type models ASN.1 NULL. + + .. automethod:: pyasn1.type.univ.Null.clone(value=NoValue(), tagSet=TagSet()) + .. automethod:: pyasn1.type.univ.Null.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/objectidentifier.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/objectidentifier.rst new file mode 100644 index 000000000000..c63140f70939 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/objectidentifier.rst @@ -0,0 +1,15 @@ + +.. |ASN.1| replace:: ObjectIdentifier + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.ObjectIdentifier(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, isPrefixOf + + .. note:: + + The |ASN.1| type models ASN.1 OBJECT IDENTIFIER as a sequence of integer numbers. + + .. automethod:: pyasn1.type.univ.ObjectIdentifier.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.ObjectIdentifier.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(), subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/octetstring.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/octetstring.rst new file mode 100644 index 000000000000..a58476d2577f --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/octetstring.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: OctetString + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.OctetString(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1', binValue=NoValue(),hexValue=NoValue()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, fromHexString, fromBinaryString + + .. note:: + + The |ASN.1| type models an arbitrary string of octets (eight-bit numbers), not printable text string. + + .. automethod:: pyasn1.type.univ.OctetString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1') + .. automethod:: pyasn1.type.univ.OctetString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(),encoding='iso-8859-1') diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/real.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/real.rst new file mode 100644 index 000000000000..f80c72590082 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/real.rst @@ -0,0 +1,15 @@ + +.. |ASN.1| replace:: Real + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Real(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec, isInf, isPlusInf, isMinusInf + + .. note:: + + The |ASN.1| type models a rational number of arbitrary precision. + + .. automethod:: pyasn1.type.univ.Real.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.Real.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(), subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/sequence.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/sequence.rst new file mode 100644 index 000000000000..d9123d8055b7 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/sequence.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: Sequence + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Sequence(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, getComponentByPosition, + setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents + + .. note:: + + The |ASN.1| type models a collection of named ASN.1 components. + Ordering of the components **is** preserved upon de/serialization. + + .. automethod:: pyasn1.type.univ.Sequence.clone(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.Sequence.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/sequenceof.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/sequenceof.rst new file mode 100644 index 000000000000..8f5c6f32ee34 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/sequenceof.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: SequenceOf + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.SequenceOf(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, + getComponentByPosition, setComponentByPosition + + .. note:: + + The |ASN.1| type models a collection of elements of a single ASN.1 type. + Ordering of the components **is** preserved upon de/serialization. + + .. automethod:: pyasn1.type.univ.SequenceOf.clone(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.SequenceOf.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/set.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/set.rst new file mode 100644 index 000000000000..621621005250 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/set.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: Set + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.Set(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, + getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents, + getComponentByType, setComponentByType + + .. note:: + + The |ASN.1| type models a collection of named ASN.1 components. + Ordering of the components **is not** preserved upon de/serialization. + + .. automethod:: pyasn1.type.univ.Set.clone(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.Set.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/univ/setof.rst b/third_party/python/pyasn1/doc/source/docs/type/univ/setof.rst new file mode 100644 index 000000000000..74fdd42e1606 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/univ/setof.rst @@ -0,0 +1,17 @@ + +.. |ASN.1| replace:: SetOf + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.univ.SetOf(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection()) + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, +  getComponentByPosition, setComponentByPosition + + .. note:: + + The |ASN.1| type models a collection of elements of a single ASN.1 type. + Ordering of the components **is not** preserved upon de/serialization. + + .. automethod:: pyasn1.type.univ.SetOf.clone(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection()) + .. automethod:: pyasn1.type.univ.SetOf.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection()) diff --git a/third_party/python/pyasn1/doc/source/docs/type/useful/contents.rst b/third_party/python/pyasn1/doc/source/docs/type/useful/contents.rst new file mode 100644 index 000000000000..c8db8af29da8 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/useful/contents.rst @@ -0,0 +1,10 @@ + +Useful types +------------ + +.. toctree:: + :maxdepth: 2 + + /docs/type/useful/objectdescriptor + /docs/type/useful/generalizedtime + /docs/type/useful/utctime diff --git a/third_party/python/pyasn1/doc/source/docs/type/useful/generalizedtime.rst b/third_party/python/pyasn1/doc/source/docs/type/useful/generalizedtime.rst new file mode 100644 index 000000000000..abf435168ad5 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/useful/generalizedtime.rst @@ -0,0 +1,35 @@ + +.. |ASN.1| replace:: GeneralizedTime + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.useful.GeneralizedTime(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, asDateTime, fromDateTime + + .. note:: + + + The |ASN.1| type models a character string representing date and time + in many different formats. + + Formal syntax for the *GeneralizedTime* value is: + + * **YYYYMMDDhh[mm[ss[(.|,)ffff]]]** standing for a local time, four + digits for the year, two for the month, two for the day and two + for the hour, followed by two digits for the minutes and two + for the seconds if required, then a dot (or a comma), and a + number for the fractions of second or + + * a string as above followed by the letter “Z” (denoting a UTC + time) or + + * a string as above followed by a string **(+|-)hh[mm]** denoting + time zone offset relative to UTC + + For example, *20170126120000Z* stands for YYYYMMDDHHMMSSZ. + + .. automethod:: pyasn1.type.useful.GeneralizedTime.clone(self, value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.useful.GeneralizedTime.subtype(self, value=NoValue(), implicitTag=TagSet(), explicitTag=TagSet(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/useful/objectdescriptor.rst b/third_party/python/pyasn1/doc/source/docs/type/useful/objectdescriptor.rst new file mode 100644 index 000000000000..3b62a5df0d58 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/useful/objectdescriptor.rst @@ -0,0 +1,18 @@ + +.. |ASN.1| replace:: ObjectDescriptor + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.useful.ObjectDescriptor(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet + + .. note:: + + The |ASN.1| type models a character string that can accompany the *ObjectIdentifier* type + to serve as a human-friendly annotation for an OBJECT IDENTIFIER. + + .. automethod:: pyasn1.type.useful.ObjectDescriptor.clone(self, value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.useful.ObjectDescriptor.subtype(self, value=NoValue(), implicitTag=TagSet(), explicitTag=TagSet(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/docs/type/useful/utctime.rst b/third_party/python/pyasn1/doc/source/docs/type/useful/utctime.rst new file mode 100644 index 000000000000..2ad86a94ff78 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/docs/type/useful/utctime.rst @@ -0,0 +1,32 @@ + +.. |ASN.1| replace:: UTCTime + +.. |encoding| replace:: iso-8859-1 + +|ASN.1| type +------------ + +.. autoclass:: pyasn1.type.useful.UTCTime(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, asDateTime, fromDateTime + + .. note:: + + The |ASN.1| type models a character string representing date and time. + + Formal syntax for the *UTCTime* value is: + + * **YYMMDDhhmm[ss]** standing for UTC time, two + digits for the year, two for the month, two for the day and two + for the hour, followed by two digits for the minutes and two + for the seconds if required or + + * a string as above followed by the letter “Z” (denoting a UTC + time) or + + * a string as above followed by a string **(+|-)hhmm** denoting + time zone offset relative to UTC + + For example, *170126120000Z* which stands for YYMMDDHHMMSSZ. + + .. automethod:: pyasn1.type.useful.UTCTime.clone(self, value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') + .. automethod:: pyasn1.type.useful.UTCTime.subtype(self, value=NoValue(), implicitTag=TagSet(), explicitTag=TagSet(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii') diff --git a/third_party/python/pyasn1/doc/source/example-use-case.rst b/third_party/python/pyasn1/doc/source/example-use-case.rst new file mode 100644 index 000000000000..d5be0cd0898b --- /dev/null +++ b/third_party/python/pyasn1/doc/source/example-use-case.rst @@ -0,0 +1,193 @@ + +Example use case +================ + +.. toctree:: + :maxdepth: 2 + +To briefly explain how to approach pyasn1, consider a quick workflow example. + +Grab ASN.1 schema for SSH keys +------------------------------ + +ASN.1 is widely used in many Internet protocols. Frequently, whenever ASN.1 is employed, +data structures are described in ASN.1 schema language right in the RFC. +Take `RFC2437 `_ for example -- we can look into +it and weed out data structures specification into a local file: + +.. code-block:: python + + # pkcs-1.asn + + PKCS-1 {iso(1) member(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) modules(0) pkcs-1(1)} + + DEFINITIONS EXPLICIT TAGS ::= BEGIN + RSAPrivateKey ::= SEQUENCE { + version Version, + modulus INTEGER, + publicExponent INTEGER, + privateExponent INTEGER, + prime1 INTEGER, + prime2 INTEGER, + exponent1 INTEGER, + exponent2 INTEGER, + coefficient INTEGER + } + Version ::= INTEGER + END + +Compile ASN.1 schema into Python +-------------------------------- + +In the best case, you should be able to automatically compile ASN.1 spec into +Python classes. For that purpose we have the `asn1ate `_ +tool: + +.. code-block:: bash + + $ pyasn1gen.py pkcs-1.asn > rsakey.py + +Though it may not work out as, as it stands now, asn1ate does not support +all ASN.1 language constructs. + +Alternatively, you could check out the `pyasn1-modules `_ +package to see if it already has the ASN.1 spec you are looking for compiled and shipped +there. Then just install the package, import the data structure you need and use it: + +.. code-block:: bash + + $ pip install pyasn1-modules + +As a last resort, you could express ASN.1 in Python by hand. The end result +should be a declarative Python code resembling original ASN.1 syntax like +this: + +.. code-block:: python + + # rsakey.py + + class Version(Integer): + pass + + class RSAPrivateKey(Sequence): + componentType = NamedTypes( + NamedType('version', Version()), + NamedType('modulus', Integer()), + NamedType('publicExponent', Integer()), + NamedType('privateExponent', Integer()), + NamedType('prime1', Integer()), + NamedType('prime2', Integer()), + NamedType('exponent1', Integer()), + NamedType('exponent2', Integer()), + NamedType('coefficient', Integer()) + ) + +Read your ~/.ssh/id_rsa +----------------------- + +Given we've put our Python classes into the `rsakey.py` module, we could import +the top-level object for SSH keys container and initialize it from our +`~/.ssh/id_rsa` file (for sake of simplicity here we assume no passphrase is +set on the key file): + +.. code-block:: python + + from base64 import b64decode + from pyasn1.codec.der.decoder import decode as der_decoder + from rsakey import RSAPrivateKey + + # Read SSH key from file (assuming no passphrase) + with open open('.ssh/id_rsa') as key_file: + b64_serialization = ''.join(key_file.readlines()[1:-1]) + + # Undo BASE64 serialization + der_serialization = b64decode(b64_serialization) + + # Undo DER serialization, reconstruct SSH key structure + private_key, rest_of_input = der_decoder(der_serialization, asn1Spec=RSAPrivateKey()) + +Once we have Python ASN.1 structures initialized, we could inspect them: + +.. code-block:: pycon + + >>> print(private_key.prettyPrint()) + RSAPrivateKey: + version=0 + modulus=280789907761334970323210643584308373... + publicExponent=65537 + privateExponent=1704567874679144879123080924... + prime1=1780178536719561265324798296279384073... + prime2=1577313184995269616049017780493740138... + exponent1=1193974819720845247396384239609024... + exponent2=9240965721817961178848297404494811... + coefficient=10207364473358910343346707141115... + +Play with the keys +------------------ + +As well as use them nearly as we do with native Python types: + +.. code-block:: pycon + + >>> pk = private_key + >>> + >>> pk['prime1'] * pk['prime2'] == pk['modulus'] + True + >>> pk['prime1'] == pk['modulus'] // pk['prime2'] + True + >>> pk['exponent1'] == pk['privateExponent'] % (pk['prime1'] - 1) + True + >>> pk['exponent2'] == pk['privateExponent'] % (pk['prime2'] - 1) + True + +Technically, pyasn1 classes `emulate `_ +Python built-in types. + +Transform to built-ins +---------------------- + +ASN.1 data structures exhibit a way more complicated behaviour compared to +Python types. You may wish to simplify things by turning the whole tree of +pyasn1 objects into an analogous tree made of base Python types: + +.. code-block:: pycon + + >>> from pyasn1.codec.native.encoder import encode + >>> ... + >>> py_private_key = encode(private_key) + >>> py_private_key + {'version': 0, 'modulus': 280789907761334970323210643584308373, 'publicExponent': 65537, + 'privateExponent': 1704567874679144879123080924, 'prime1': 1780178536719561265324798296279384073, + 'prime2': 1577313184995269616049017780493740138, 'exponent1': 1193974819720845247396384239609024, + 'exponent2': 9240965721817961178848297404494811, 'coefficient': 10207364473358910343346707141115} + +You can do vice-versa: initialize ASN.1 structure from a dict: + +.. code-block:: pycon + + >>> from pyasn1.codec.native.decoder import decode + >>> py_private_key = {'modulus': 280789907761334970323210643584308373} + >>> private_key = decode(py_private_key, asn1Spec=RSAPrivateKey()) + +Write it back +------------- + +Possibly not that applicable to the SSH key example, but you can of course modify +any part of the ASN.1 data structure and serialize it back into the same or other +wire representation: + +.. code-block:: python + + from pyasn1.codec.der.encoder import encode as der_encoder + + # Serialize SSH key data structure into DER stream + der_serialization = der_encoder(private_key) + + # Serialize DER stream into BASE64 stream + b64_serialization = '-----BEGIN RSA PRIVATE KEY-----\n' + b64_serialization += b64encode(der_serialization) + b64_serialization += '-----END RSA PRIVATE KEY-----\n' + + with open('.ssh/id_rsa.new', 'w') as key_file: + key_file.write(b64_serialization) + diff --git a/third_party/python/pyasn1/doc/source/license.rst b/third_party/python/pyasn1/doc/source/license.rst new file mode 100644 index 000000000000..643baf105308 --- /dev/null +++ b/third_party/python/pyasn1/doc/source/license.rst @@ -0,0 +1,6 @@ +.. _license: + +License +======= + +.. include:: ../../LICENSE.rst diff --git a/third_party/python/pyasn1/doc/tagging.html b/third_party/python/pyasn1/doc/tagging.html deleted file mode 100644 index 187f1180d29d..000000000000 --- a/third_party/python/pyasn1/doc/tagging.html +++ /dev/null @@ -1,233 +0,0 @@ - - -Tagging in PyASN1 - - - - -
- - - - -
- -

-1.2 Tagging in PyASN1 -

- -

-In order to continue with the Constructed ASN.1 types, we will first have -to introduce the concept of tagging (and its pyasn1 implementation), as -some of the Constructed types rely upon the tagging feature. -

- -

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

- -
-
-MyIntegerType ::= [12] INTEGER
-MyOctetString ::= [APPLICATION 0] OCTET STRING
-
-
- -

-In pyasn1, tags are implemented as immutable, tuple-like objects: -

- -
-
->>> 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. -

- -
-
-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. -

- -
-
->>> from pyasn1.type import tag
->>> tagSet = tag.TagSet(
-...   # base tag
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10),
-...   # effective tag
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
-... )
->>> tagSet
-TagSet(Tag(tagClass=128, tagFormat=0, tagId=10))
->>> tagSet.getBaseTag()
-Tag(tagClass=128, tagFormat=0, tagId=10)
->>> tagSet = tagSet.tagExplicitly(
-...    tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20)
-... )
->>> tagSet
-TagSet(Tag(tagClass=128, tagFormat=0, tagId=10), 
-       Tag(tagClass=128, tagFormat=32, tagId=20))
->>> tagSet = tagSet.tagExplicitly(
-...    tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 30)
-... )
->>> tagSet
-TagSet(Tag(tagClass=128, tagFormat=0, tagId=10), 
-       Tag(tagClass=128, tagFormat=32, tagId=20), 
-       Tag(tagClass=128, tagFormat=32, tagId=30))
->>> tagSet = tagSet.tagImplicitly(
-...    tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)
-... )
->>> tagSet
-TagSet(Tag(tagClass=128, tagFormat=0, tagId=10),
-       Tag(tagClass=128, tagFormat=32, tagId=20),
-       Tag(tagClass=128, tagFormat=32, tagId=40))
->>> 
-
-
- -

-As a side note: the "base tag" concept (accessible through the getBaseTag() -method) is specific to pyasn1 -- the base tag is used to identify the original -ASN.1 type of an object in question. Base tag is never occurs in encoding -and is mostly used internally by pyasn1 for choosing type-specific data -processing algorithms. The "effective tag" is the one that always appears in -encoding and is used on tagSets comparation. -

- -

-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. -

- -
-
->>> from pyasn1.type import tag
->>> tagSet1 = tag.TagSet(
-...   # base tag
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
-...   # effective tag
-...   tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
-... )
->>> tagSet2 = tagSet1.tagExplicitly(
-...    tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20)
-... )
->>> tagSet1.isSuperTagSetOf(tagSet2)
-True
->>> tagSet2.isSuperTagSetOf(tagSet1)
-False
->>> 
-
-
- -

-We will complete this discussion on tagging with a real-world example. The -following ASN.1 tagged type: -

- -
-
-MyIntegerType ::= [12] EXPLICIT INTEGER
-
-
- -

-could be expressed in pyasn1 like this: -

- -
-
->>> from pyasn1.type import univ, tag
->>> class MyIntegerType(univ.Integer):
-...   tagSet = univ.Integer.tagSet.tagExplicitly(
-...        tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12)
-...        )
->>> myInteger = MyIntegerType(12345)
->>> myInteger.getTagSet()
-TagSet(Tag(tagClass=0, tagFormat=0, tagId=2), 
-       Tag(tagClass=128, tagFormat=32, tagId=12))
->>>
-
-
- -

-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. -

- -
- -
-
- - diff --git a/third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO b/third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO index 5de78eceb04d..4454cb1caeb0 100644 --- a/third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO +++ b/third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO @@ -1,26 +1,33 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: pyasn1 -Version: 0.1.7 +Version: 0.3.7 Summary: ASN.1 types and codecs -Home-page: http://sourceforge.net/projects/pyasn1/ -Author: Ilya Etingof -Author-email: ilya@glas.net +Home-page: https://github.com/etingof/pyasn1 +Author: Ilya Etingof +Author-email: etingof@gmail.com License: BSD -Description: A pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208). +Description: Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208) Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: Science/Research Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.4 +Classifier: Programming Language :: Python :: 2.5 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Communications -Classifier: Topic :: Security :: Cryptography Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt b/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt index 615608dd8725..53a7b011347e 100644 --- a/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt +++ b/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt @@ -1,17 +1,66 @@ -CHANGES -LICENSE +CHANGES.rst +LICENSE.rst MANIFEST.in -README -THANKS -TODO +README.md +TODO.rst +setup.cfg setup.py -doc/codecs.html -doc/constraints.html -doc/constructed.html -doc/intro.html -doc/pyasn1-tutorial.html -doc/scalar.html -doc/tagging.html +doc/Makefile +doc/source/changelog.rst +doc/source/conf.py +doc/source/contents.rst +doc/source/example-use-case.rst +doc/source/license.rst +doc/source/docs/api-reference.rst +doc/source/docs/tutorial.rst +doc/source/docs/codec/ber/contents.rst +doc/source/docs/codec/cer/contents.rst +doc/source/docs/codec/der/contents.rst +doc/source/docs/codec/native/contents.rst +doc/source/docs/type/char/bmpstring.rst +doc/source/docs/type/char/contents.rst +doc/source/docs/type/char/generalstring.rst +doc/source/docs/type/char/graphicstring.rst +doc/source/docs/type/char/ia5string.rst +doc/source/docs/type/char/iso646string.rst +doc/source/docs/type/char/numericstring.rst +doc/source/docs/type/char/printablestring.rst +doc/source/docs/type/char/t61string.rst +doc/source/docs/type/char/teletexstring.rst +doc/source/docs/type/char/universalstring.rst +doc/source/docs/type/char/utf8string.rst +doc/source/docs/type/char/videotexstring.rst +doc/source/docs/type/char/visiblestring.rst +doc/source/docs/type/namedtype/contents.rst +doc/source/docs/type/namedtype/defaultednamedtype.rst +doc/source/docs/type/namedtype/namedtype.rst +doc/source/docs/type/namedtype/namedtypes.rst +doc/source/docs/type/namedtype/optionalnamedtype.rst +doc/source/docs/type/namedval/contents.rst +doc/source/docs/type/namedval/namedval.rst +doc/source/docs/type/tag/contents.rst +doc/source/docs/type/tag/tag.rst +doc/source/docs/type/tag/tagmap.rst +doc/source/docs/type/tag/tagset.rst +doc/source/docs/type/univ/any.rst +doc/source/docs/type/univ/bitstring.rst +doc/source/docs/type/univ/boolean.rst +doc/source/docs/type/univ/choice.rst +doc/source/docs/type/univ/contents.rst +doc/source/docs/type/univ/enumerated.rst +doc/source/docs/type/univ/integer.rst +doc/source/docs/type/univ/null.rst +doc/source/docs/type/univ/objectidentifier.rst +doc/source/docs/type/univ/octetstring.rst +doc/source/docs/type/univ/real.rst +doc/source/docs/type/univ/sequence.rst +doc/source/docs/type/univ/sequenceof.rst +doc/source/docs/type/univ/set.rst +doc/source/docs/type/univ/setof.rst +doc/source/docs/type/useful/contents.rst +doc/source/docs/type/useful/generalizedtime.rst +doc/source/docs/type/useful/objectdescriptor.rst +doc/source/docs/type/useful/utctime.rst pyasn1/__init__.py pyasn1/debug.py pyasn1/error.py @@ -31,8 +80,16 @@ pyasn1/codec/cer/encoder.py pyasn1/codec/der/__init__.py pyasn1/codec/der/decoder.py pyasn1/codec/der/encoder.py +pyasn1/codec/native/__init__.py +pyasn1/codec/native/decoder.py +pyasn1/codec/native/encoder.py pyasn1/compat/__init__.py +pyasn1/compat/binary.py +pyasn1/compat/calling.py +pyasn1/compat/dateandtime.py +pyasn1/compat/integer.py pyasn1/compat/octets.py +pyasn1/compat/string.py pyasn1/type/__init__.py pyasn1/type/base.py pyasn1/type/char.py @@ -44,25 +101,39 @@ pyasn1/type/tag.py pyasn1/type/tagmap.py pyasn1/type/univ.py pyasn1/type/useful.py -test/__init__.py -test/suite.py -test/codec/__init__.py -test/codec/suite.py -test/codec/ber/__init__.py -test/codec/ber/suite.py -test/codec/ber/test_decoder.py -test/codec/ber/test_encoder.py -test/codec/cer/__init__.py -test/codec/cer/suite.py -test/codec/cer/test_decoder.py -test/codec/cer/test_encoder.py -test/codec/der/__init__.py -test/codec/der/suite.py -test/codec/der/test_decoder.py -test/codec/der/test_encoder.py -test/type/__init__.py -test/type/suite.py -test/type/test_constraint.py -test/type/test_namedtype.py -test/type/test_tag.py -test/type/test_univ.py \ No newline at end of file +tests/__init__.py +tests/__main__.py +tests/base.py +tests/test_debug.py +tests/codec/__init__.py +tests/codec/__main__.py +tests/codec/ber/__init__.py +tests/codec/ber/__main__.py +tests/codec/ber/test_decoder.py +tests/codec/ber/test_encoder.py +tests/codec/cer/__init__.py +tests/codec/cer/__main__.py +tests/codec/cer/test_decoder.py +tests/codec/cer/test_encoder.py +tests/codec/der/__init__.py +tests/codec/der/__main__.py +tests/codec/der/test_decoder.py +tests/codec/der/test_encoder.py +tests/codec/native/__init__.py +tests/codec/native/__main__.py +tests/codec/native/test_decoder.py +tests/codec/native/test_encoder.py +tests/compat/__init__.py +tests/compat/__main__.py +tests/compat/test_binary.py +tests/compat/test_integer.py +tests/compat/test_octets.py +tests/type/__init__.py +tests/type/__main__.py +tests/type/test_char.py +tests/type/test_constraint.py +tests/type/test_namedtype.py +tests/type/test_namedval.py +tests/type/test_tag.py +tests/type/test_univ.py +tests/type/test_useful.py \ No newline at end of file diff --git a/third_party/python/pyasn1/pyasn1/__init__.py b/third_party/python/pyasn1/pyasn1/__init__.py index 88aff79c84f9..c9218a04fa06 100644 --- a/third_party/python/pyasn1/pyasn1/__init__.py +++ b/third_party/python/pyasn1/pyasn1/__init__.py @@ -1,8 +1,7 @@ import sys # http://www.python.org/dev/peps/pep-0396/ -__version__ = '0.1.7' +__version__ = '0.3.7' if sys.version_info[:2] < (2, 4): - raise RuntimeError('PyASN1 requires Python 2.4 or later') - + raise RuntimeError('PyASN1 requires Python 2.4 or later') diff --git a/third_party/python/pyasn1/pyasn1/codec/ber/decoder.py b/third_party/python/pyasn1/pyasn1/codec/ber/decoder.py index be0cf49074d5..ee3064f3611f 100644 --- a/third_party/python/pyasn1/pyasn1/codec/ber/decoder.py +++ b/third_party/python/pyasn1/pyasn1/codec/ber/decoder.py @@ -1,235 +1,285 @@ -# BER decoder -from pyasn1.type import tag, base, univ, char, useful, tagmap +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from pyasn1.type import base, tag, univ, char, useful, tagmap from pyasn1.codec.ber import eoo -from pyasn1.compat.octets import oct2int, octs2ints, isOctetsType +from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, null +from pyasn1.compat.integer import from_bytes from pyasn1 import debug, error -class AbstractDecoder: +__all__ = ['decode'] + +noValue = base.noValue + + +class AbstractDecoder(object): protoComponent = None - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,)) - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,)) + class AbstractSimpleDecoder(AbstractDecoder): - tagFormats = (tag.tagFormatSimple,) - def _createComponent(self, asn1Spec, tagSet, value=None): - if tagSet[0][1] not in self.tagFormats: - raise error.PyAsn1Error('Invalid tag format %r for %r' % (tagSet[0], self.protoComponent,)) + @staticmethod + def substrateCollector(asn1Object, substrate, length): + return substrate[:length], substrate[length:] + + def _createComponent(self, asn1Spec, tagSet, value=noValue): if asn1Spec is None: - return self.protoComponent.clone(value, tagSet) - elif value is None: + return self.protoComponent.clone(value, tagSet=tagSet) + elif value is noValue: return asn1Spec else: return asn1Spec.clone(value) - -class AbstractConstructedDecoder(AbstractDecoder): - tagFormats = (tag.tagFormatConstructed,) - def _createComponent(self, asn1Spec, tagSet, value=None): - if tagSet[0][1] not in self.tagFormats: - raise error.PyAsn1Error('Invalid tag format %r for %r' % (tagSet[0], self.protoComponent,)) - if asn1Spec is None: - return self.protoComponent.clone(tagSet) - else: - return asn1Spec.clone() - -class EndOfOctetsDecoder(AbstractSimpleDecoder): - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - return eoo.endOfOctets, substrate[length:] + class ExplicitTagDecoder(AbstractSimpleDecoder): protoComponent = univ.Any('') - tagFormats = (tag.tagFormatConstructed,) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): if substrateFun: return substrateFun( - self._createComponent(asn1Spec, tagSet, ''), - substrate, length - ) + self._createComponent(asn1Spec, tagSet, ''), + substrate, length + ) + head, tail = substrate[:length], substrate[length:] - value, _ = decodeFun(head, asn1Spec, tagSet, length) + + value, _ = decodeFun(head, asn1Spec, tagSet, length, **options) + return value, tail - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): if substrateFun: return substrateFun( - self._createComponent(asn1Spec, tagSet, ''), - substrate, length - ) - value, substrate = decodeFun(substrate, asn1Spec, tagSet, length) - terminator, substrate = decodeFun(substrate) - if eoo.endOfOctets.isSameTypeWith(terminator) and \ - terminator == eoo.endOfOctets: + self._createComponent(asn1Spec, tagSet, ''), + substrate, length + ) + + value, substrate = decodeFun(substrate, asn1Spec, tagSet, length, **options) + + eooMarker, substrate = decodeFun(substrate, allowEoo=True, **options) + + if eooMarker is eoo.endOfOctets: return value, substrate else: raise error.PyAsn1Error('Missing end-of-octets terminator') + explicitTagDecoder = ExplicitTagDecoder() + class IntegerDecoder(AbstractSimpleDecoder): protoComponent = univ.Integer(0) - precomputedValues = { - '\x00': 0, - '\x01': 1, - '\x02': 2, - '\x03': 3, - '\x04': 4, - '\x05': 5, - '\x06': 6, - '\x07': 7, - '\x08': 8, - '\x09': 9, - '\xff': -1, - '\xfe': -2, - '\xfd': -3, - '\xfc': -4, - '\xfb': -5 - } - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + head, tail = substrate[:length], substrate[length:] + if not head: return self._createComponent(asn1Spec, tagSet, 0), tail - if head in self.precomputedValues: - value = self.precomputedValues[head] - else: - firstOctet = oct2int(head[0]) - if firstOctet & 0x80: - value = -1 - else: - value = 0 - for octet in head: - value = value << 8 | oct2int(octet) + + value = from_bytes(head, signed=True) + return self._createComponent(asn1Spec, tagSet, value), tail + class BooleanDecoder(IntegerDecoder): protoComponent = univ.Boolean(0) - def _createComponent(self, asn1Spec, tagSet, value=None): + + def _createComponent(self, asn1Spec, tagSet, value=noValue): return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0) + class BitStringDecoder(AbstractSimpleDecoder): protoComponent = univ.BitString(()) - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): + supportConstructedForm = True + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): head, tail = substrate[:length], substrate[length:] - if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check? + if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? if not head: raise error.PyAsn1Error('Empty substrate') trailingBits = oct2int(head[0]) if trailingBits > 7: raise error.PyAsn1Error( 'Trailing bits overflow %s' % trailingBits - ) - head = head[1:] - lsb = p = 0; l = len(head)-1; b = () - while p <= l: - if p == l: - lsb = trailingBits - j = 7 - o = oct2int(head[p]) - while j >= lsb: - b = b + ((o>>j)&0x01,) - j = j - 1 - p = p + 1 - return self._createComponent(asn1Spec, tagSet, b), tail - r = self._createComponent(asn1Spec, tagSet, ()) - if substrateFun: - return substrateFun(r, substrate, length) - while head: - component, head = decodeFun(head) - r = r + component - return r, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet, '') - if substrateFun: - return substrateFun(r, substrate, length) - while substrate: - component, substrate = decodeFun(substrate) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - r = r + component - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' ) - return r, substrate + head = head[1:] + value = self.protoComponent.fromOctetString(head, trailingBits) + return self._createComponent(asn1Spec, tagSet, value), tail + + if not self.supportConstructedForm: + raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) + + bitString = self._createComponent(asn1Spec, tagSet) + + if substrateFun: + return substrateFun(bitString, substrate, length) + + while head: + component, head = decodeFun(head, self.protoComponent, **options) + bitString += component + + return bitString, tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + bitString = self._createComponent(asn1Spec, tagSet) + + if substrateFun: + return substrateFun(bitString, substrate, length) + + while substrate: + component, substrate = decodeFun(substrate, self.protoComponent, + allowEoo=True, **options) + if component is eoo.endOfOctets: + break + + bitString += component + + else: + raise error.SubstrateUnderrunError('No EOO seen before substrate ends') + + return bitString, substrate + class OctetStringDecoder(AbstractSimpleDecoder): protoComponent = univ.OctetString('') - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check? - return self._createComponent(asn1Spec, tagSet, head), tail - r = self._createComponent(asn1Spec, tagSet, '') - if substrateFun: - return substrateFun(r, substrate, length) - while head: - component, head = decodeFun(head) - r = r + component - return r, tail + supportConstructedForm = True + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + head, tail = substrate[:length], substrate[length:] - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet, '') if substrateFun: - return substrateFun(r, substrate, length) + return substrateFun(self._createComponent(asn1Spec, tagSet), + substrate, length) + + if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? + return self._createComponent(asn1Spec, tagSet, head), tail + + if not self.supportConstructedForm: + raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + header = null + + while head: + component, head = decodeFun(head, self.protoComponent, + substrateFun=substrateFun, + **options) + header += component + + return self._createComponent(asn1Spec, tagSet, header), tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun and substrateFun is not self.substrateCollector: + asn1Object = self._createComponent(asn1Spec, tagSet) + return substrateFun(asn1Object, substrate, length) + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + header = null + while substrate: - component, substrate = decodeFun(substrate) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: + component, substrate = decodeFun(substrate, + self.protoComponent, + substrateFun=substrateFun, + allowEoo=True, **options) + if component is eoo.endOfOctets: break - r = r + component + header += component else: raise error.SubstrateUnderrunError( 'No EOO seen before substrate ends' - ) - return r, substrate + ) + + return self._createComponent(asn1Spec, tagSet, header), substrate + class NullDecoder(AbstractSimpleDecoder): protoComponent = univ.Null('') - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) + + component = self._createComponent(asn1Spec, tagSet) + if head: raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length) - return r, tail + + return component, tail + class ObjectIdentifierDecoder(AbstractSimpleDecoder): protoComponent = univ.ObjectIdentifier(()) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + head, tail = substrate[:length], substrate[length:] if not head: raise error.PyAsn1Error('Empty substrate') - # Get the first subid - subId = oct2int(head[0]) - oid = divmod(subId, 40) + head = octs2ints(head) - index = 1 + oid = () + index = 0 substrateLen = len(head) while index < substrateLen: - subId = oct2int(head[index]) - index = index + 1 - if subId == 128: - # ASN.1 spec forbids leading zeros (0x80) in sub-ID OID - # encoding, tolerating it opens a vulnerability. - # See http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf page 7 - raise error.PyAsn1Error('Invalid leading 0x80 in sub-OID') + subId = head[index] + index += 1 + if subId < 128: + oid += (subId,) elif subId > 128: # Construct subid from a number of octets nextSubId = subId @@ -239,44 +289,84 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder): if index >= substrateLen: raise error.SubstrateUnderrunError( 'Short substrate for sub-OID past %s' % (oid,) - ) - nextSubId = oct2int(head[index]) - index = index + 1 - subId = (subId << 7) + nextSubId - oid = oid + (subId,) + ) + nextSubId = head[index] + index += 1 + oid += ((subId << 7) + nextSubId,) + elif subId == 128: + # ASN.1 spec forbids leading zeros (0x80) in OID + # encoding, tolerating it opens a vulnerability. See + # http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf + # page 7 + raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding') + + # Decode two leading arcs + if 0 <= oid[0] <= 39: + oid = (0,) + oid + elif 40 <= oid[0] <= 79: + oid = (1, oid[0] - 40) + oid[1:] + elif oid[0] >= 80: + oid = (2, oid[0] - 80) + oid[1:] + else: + raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0]) + return self._createComponent(asn1Spec, tagSet, oid), tail + class RealDecoder(AbstractSimpleDecoder): protoComponent = univ.Real() - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + head, tail = substrate[:length], substrate[length:] + if not head: return self._createComponent(asn1Spec, tagSet, 0.0), tail - fo = oct2int(head[0]); head = head[1:] - if fo & 0x80: # binary enoding + + fo = oct2int(head[0]) + head = head[1:] + if fo & 0x80: # binary encoding + if not head: + raise error.PyAsn1Error("Incomplete floating-point value") n = (fo & 0x03) + 1 if n == 4: n = oct2int(head[0]) + head = head[1:] eo, head = head[:n], head[n:] if not eo or not head: raise error.PyAsn1Error('Real exponent screwed') e = oct2int(eo[0]) & 0x80 and -1 or 0 - while eo: # exponent + while eo: # exponent e <<= 8 e |= oct2int(eo[0]) eo = eo[1:] + b = fo >> 4 & 0x03 # base bits + if b > 2: + raise error.PyAsn1Error('Illegal Real base') + if b == 1: # encbase = 8 + e *= 3 + elif b == 2: # encbase = 16 + e *= 4 p = 0 while head: # value p <<= 8 p |= oct2int(head[0]) head = head[1:] - if fo & 0x40: # sign bit + if fo & 0x40: # sign bit p = -p + sf = fo >> 2 & 0x03 # scale bits + p *= 2 ** sf value = (p, 2, e) elif fo & 0x40: # infinite value value = fo & 0x01 and '-inf' or 'inf' elif fo & 0xc0 == 0: # character encoding + if not head: + raise error.PyAsn1Error("Incomplete floating-point value") try: if fo & 0x3 == 0x1: # NR1 value = (int(head), 10, 0) @@ -287,247 +377,480 @@ class RealDecoder(AbstractSimpleDecoder): else: raise error.SubstrateUnderrunError( 'Unknown NR (tag %s)' % fo - ) + ) except ValueError: raise error.SubstrateUnderrunError( 'Bad character Real syntax' - ) + ) else: raise error.SubstrateUnderrunError( 'Unknown encoding (tag %s)' % fo - ) + ) return self._createComponent(asn1Spec, tagSet, value), tail - -class SequenceDecoder(AbstractConstructedDecoder): + + +class AbstractConstructedDecoder(AbstractDecoder): + protoComponent = None + + +class UniversalConstructedTypeDecoder(AbstractConstructedDecoder): + protoRecordComponent = None + protoSequenceComponent = None + + def _getComponentTagMap(self, asn1Object, idx): + raise NotImplementedError() + + def _getComponentPositionByType(self, asn1Object, tagSet, idx): + raise NotImplementedError() + + def _decodeComponents(self, substrate, tagSet=None, decodeFun=None, **options): + components = [] + componentTypes = set() + while substrate: + component, substrate = decodeFun(substrate, **options) + if component is eoo.endOfOctets: + break + components.append(component) + componentTypes.add(component.tagSet) + + # Now we have to guess is it SEQUENCE/SET or SEQUENCE OF/SET OF + # The heuristics is: + # * 0-1 component -> likely SEQUENCE OF/SET OF + # * 1+ components of the same type -> likely SEQUENCE OF/SET OF + # * otherwise -> likely SEQUENCE/SET + if len(components) > 1 or len(componentTypes) > 1: + protoComponent = self.protoRecordComponent + else: + protoComponent = self.protoSequenceComponent + + asn1Object = protoComponent.clone( + # construct tagSet from base tag from prototype ASN.1 object + # and additional tags recovered from the substrate + tagSet=tag.TagSet(protoComponent.tagSet.baseTag, *tagSet.superTags) + ) + + for idx, component in enumerate(components): + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + return asn1Object, substrate + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatConstructed: + raise error.PyAsn1Error('Constructed tag format expected') + + head, tail = substrate[:length], substrate[length:] + + if substrateFun is not None: + if asn1Spec is not None: + asn1Object = asn1Spec.clone() + elif self.protoComponent is not None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + else: + asn1Object = self.protoRecordComponent, self.protoSequenceComponent + + return substrateFun(asn1Object, substrate, length) + + if asn1Spec is None: + asn1Object, trailing = self._decodeComponents( + head, tagSet=tagSet, decodeFun=decodeFun, **options + ) + if trailing: + raise error.PyAsn1Error('Unused trailing %d octets encountered' % len(trailing)) + return asn1Object, tail + + asn1Object = asn1Spec.clone() + + if asn1Object.typeId in (univ.Sequence.typeId, univ.Set.typeId): + + namedTypes = asn1Object.componentType + + isSetType = asn1Object.typeId == univ.Set.typeId + isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault + + seenIndices = set() + idx = 0 + while head: + if not namedTypes: + asn1Spec = None + elif isSetType: + asn1Spec = namedTypes.tagMapUnique + else: + try: + if isDeterministic: + asn1Spec = namedTypes[idx].asn1Object + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + asn1Spec = namedTypes.getTagMapNearPosition(idx) + else: + asn1Spec = namedTypes[idx].asn1Object + except IndexError: + raise error.PyAsn1Error( + 'Excessive components decoded at %r' % (asn1Object,) + ) + + component, head = decodeFun(head, asn1Spec, **options) + + if not isDeterministic and namedTypes: + if isSetType: + idx = namedTypes.getPositionByType(component.effectiveTagSet) + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + idx = namedTypes.getPositionNearType(component.effectiveTagSet, idx) + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + seenIndices.add(idx) + idx += 1 + + if namedTypes: + if not namedTypes.requiredComponents.issubset(seenIndices): + raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) + else: + asn1Object.verifySizeSpec() + + else: + asn1Spec = asn1Object.componentType + idx = 0 + while head: + component, head = decodeFun(head, asn1Spec, **options) + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + idx += 1 + + asn1Object.verifySizeSpec() + + return asn1Object, tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatConstructed: + raise error.PyAsn1Error('Constructed tag format expected') + + if substrateFun is not None: + if asn1Spec is not None: + asn1Object = asn1Spec.clone() + elif self.protoComponent is not None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + else: + asn1Object = self.protoRecordComponent, self.protoSequenceComponent + + return substrateFun(asn1Object, substrate, length) + + if asn1Spec is None: + return self._decodeComponents( + substrate, tagSet=tagSet, decodeFun=decodeFun, allowEoo=True, **options + ) + + asn1Object = asn1Spec.clone() + + if asn1Object.typeId in (univ.Sequence.typeId, univ.Set.typeId): + + namedTypes = asn1Object.componentType + + isSetType = asn1Object.typeId == univ.Set.typeId + isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault + + seenIndices = set() + idx = 0 + while substrate: + if len(namedTypes) <= idx: + asn1Spec = None + elif isSetType: + asn1Spec = namedTypes.tagMapUnique + else: + try: + if isDeterministic: + asn1Spec = namedTypes[idx].asn1Object + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + asn1Spec = namedTypes.getTagMapNearPosition(idx) + else: + asn1Spec = namedTypes[idx].asn1Object + except IndexError: + raise error.PyAsn1Error( + 'Excessive components decoded at %r' % (asn1Object,) + ) + + component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True, **options) + if component is eoo.endOfOctets: + break + + if not isDeterministic and namedTypes: + if isSetType: + idx = namedTypes.getPositionByType(component.effectiveTagSet) + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + idx = namedTypes.getPositionNearType(component.effectiveTagSet, idx) + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + seenIndices.add(idx) + idx += 1 + + else: + raise error.SubstrateUnderrunError( + 'No EOO seen before substrate ends' + ) + + if namedTypes: + if not namedTypes.requiredComponents.issubset(seenIndices): + raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) + else: + asn1Object.verifySizeSpec() + + else: + asn1Spec = asn1Object.componentType + idx = 0 + while substrate: + component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True, **options) + if component is eoo.endOfOctets: + break + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + idx += 1 + else: + raise error.SubstrateUnderrunError( + 'No EOO seen before substrate ends' + ) + asn1Object.verifySizeSpec() + + return asn1Object, substrate + + +class SequenceOrSequenceOfDecoder(UniversalConstructedTypeDecoder): + protoRecordComponent = univ.Sequence() + protoSequenceComponent = univ.SequenceOf() + + +class SequenceDecoder(SequenceOrSequenceOfDecoder): protoComponent = univ.Sequence() - def _getComponentTagMap(self, r, idx): - try: - return r.getComponentTagMapNearPosition(idx) - except error.PyAsn1Error: - return - def _getComponentPositionByType(self, r, t, idx): - return r.getComponentPositionNearType(t, idx) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - idx = 0 - if substrateFun: - return substrateFun(r, substrate, length) - while head: - asn1Spec = self._getComponentTagMap(r, idx) - component, head = decodeFun(head, asn1Spec) - idx = self._getComponentPositionByType( - r, component.getEffectiveTagSet(), idx - ) - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - r.setDefaultComponents() - r.verifySizeSpec() - return r, tail - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - idx = 0 - while substrate: - asn1Spec = self._getComponentTagMap(r, idx) - component, substrate = decodeFun(substrate, asn1Spec) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - idx = self._getComponentPositionByType( - r, component.getEffectiveTagSet(), idx - ) - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - r.setDefaultComponents() - r.verifySizeSpec() - return r, substrate +class SequenceOfDecoder(SequenceOrSequenceOfDecoder): + protoComponent = univ.SequenceOf() -class SequenceOfDecoder(AbstractConstructedDecoder): - protoComponent = univ.SequenceOf() - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - asn1Spec = r.getComponentType() - idx = 0 - while head: - component, head = decodeFun(head, asn1Spec) - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - r.verifySizeSpec() - return r, tail - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - asn1Spec = r.getComponentType() - idx = 0 - while substrate: - component, substrate = decodeFun(substrate, asn1Spec) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - r.verifySizeSpec() - return r, substrate +class SetOrSetOfDecoder(UniversalConstructedTypeDecoder): + protoRecordComponent = univ.Set() + protoSequenceComponent = univ.SetOf() -class SetDecoder(SequenceDecoder): + +class SetDecoder(SetOrSetOfDecoder): protoComponent = univ.Set() - def _getComponentTagMap(self, r, idx): - return r.getComponentTagMap() - def _getComponentPositionByType(self, r, t, idx): - nextIdx = r.getComponentPositionByType(t) - if nextIdx is None: - return idx - else: - return nextIdx - -class SetOfDecoder(SequenceOfDecoder): + + +class SetOfDecoder(SetOrSetOfDecoder): protoComponent = univ.SetOf() - + + class ChoiceDecoder(AbstractConstructedDecoder): protoComponent = univ.Choice() - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - if r.getTagSet() == tagSet: # explicitly tagged Choice - component, head = decodeFun( - head, r.getComponentTagMap() - ) - else: - component, head = decodeFun( - head, r.getComponentTagMap(), tagSet, length, state - ) - if isinstance(component, univ.Choice): - effectiveTagSet = component.getEffectiveTagSet() - else: - effectiveTagSet = component.getTagSet() - r.setComponentByType(effectiveTagSet, component, 0, asn1Spec is None) - return r, tail - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet) + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + head, tail = substrate[:length], substrate[length:] + if asn1Spec is None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + else: + asn1Object = asn1Spec.clone() if substrateFun: - return substrateFun(r, substrate, length) - if r.getTagSet() == tagSet: # explicitly tagged Choice - component, substrate = decodeFun(substrate, r.getComponentTagMap()) - eooMarker, substrate = decodeFun(substrate) # eat up EOO marker - if not eoo.endOfOctets.isSameTypeWith(eooMarker) or \ - eooMarker != eoo.endOfOctets: + return substrateFun(asn1Object, substrate, length) + if asn1Object.tagSet == tagSet: # explicitly tagged Choice + component, head = decodeFun( + head, asn1Object.componentTagMap, **options + ) + else: + component, head = decodeFun( + head, asn1Object.componentTagMap, + tagSet, length, state, **options + ) + effectiveTagSet = component.effectiveTagSet + asn1Object.setComponentByType( + effectiveTagSet, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=False + ) + return asn1Object, tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + else: + asn1Object = asn1Spec.clone() + if substrateFun: + return substrateFun(asn1Object, substrate, length) + if asn1Object.tagSet == tagSet: # explicitly tagged Choice + component, substrate = decodeFun( + substrate, asn1Object.componentType.tagMapUnique, **options + ) + # eat up EOO marker + eooMarker, substrate = decodeFun( + substrate, allowEoo=True, **options + ) + if eooMarker is not eoo.endOfOctets: raise error.PyAsn1Error('No EOO seen before substrate ends') else: - component, substrate= decodeFun( - substrate, r.getComponentTagMap(), tagSet, length, state + component, substrate = decodeFun( + substrate, asn1Object.componentType.tagMapUnique, + tagSet, length, state, **options ) - if isinstance(component, univ.Choice): - effectiveTagSet = component.getEffectiveTagSet() - else: - effectiveTagSet = component.getTagSet() - r.setComponentByType(effectiveTagSet, component, 0, asn1Spec is None) - return r, substrate + effectiveTagSet = component.effectiveTagSet + asn1Object.setComponentByType( + effectiveTagSet, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=False + ) + return asn1Object, substrate + class AnyDecoder(AbstractSimpleDecoder): protoComponent = univ.Any() - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if asn1Spec is None or \ - asn1Spec is not None and tagSet != asn1Spec.getTagSet(): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None or asn1Spec is not None and tagSet != asn1Spec.tagSet: + fullSubstrate = options['fullSubstrate'] + # untagged Any container, recover inner header substrate - length = length + len(fullSubstrate) - len(substrate) + length += len(fullSubstrate) - len(substrate) substrate = fullSubstrate + if substrateFun: return substrateFun(self._createComponent(asn1Spec, tagSet), substrate, length) + head, tail = substrate[:length], substrate[length:] + return self._createComponent(asn1Spec, tagSet, value=head), tail - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if asn1Spec is not None and tagSet == asn1Spec.getTagSet(): + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is not None and tagSet == asn1Spec.tagSet: # tagged Any type -- consume header substrate - header = '' + header = null else: + fullSubstrate = options['fullSubstrate'] + # untagged Any, recover header substrate header = fullSubstrate[:-len(substrate)] - r = self._createComponent(asn1Spec, tagSet, header) - # Any components do not inherit initial tag asn1Spec = self.protoComponent - - if substrateFun: - return substrateFun(r, substrate, length) + + if substrateFun and substrateFun is not self.substrateCollector: + asn1Object = self._createComponent(asn1Spec, tagSet) + return substrateFun(asn1Object, header + substrate, length + len(header)) + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + while substrate: - component, substrate = decodeFun(substrate, asn1Spec) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: + component, substrate = decodeFun(substrate, asn1Spec, + substrateFun=substrateFun, + allowEoo=True, **options) + if component is eoo.endOfOctets: break - r = r + component + header += component else: raise error.SubstrateUnderrunError( 'No EOO seen before substrate ends' - ) - return r, substrate + ) + if substrateFun: + return header, substrate + else: + return self._createComponent(asn1Spec, tagSet, header), substrate + # character string types class UTF8StringDecoder(OctetStringDecoder): protoComponent = char.UTF8String() + + class NumericStringDecoder(OctetStringDecoder): protoComponent = char.NumericString() + + class PrintableStringDecoder(OctetStringDecoder): protoComponent = char.PrintableString() + + class TeletexStringDecoder(OctetStringDecoder): protoComponent = char.TeletexString() + + class VideotexStringDecoder(OctetStringDecoder): protoComponent = char.VideotexString() + + class IA5StringDecoder(OctetStringDecoder): protoComponent = char.IA5String() + + class GraphicStringDecoder(OctetStringDecoder): protoComponent = char.GraphicString() + + class VisibleStringDecoder(OctetStringDecoder): protoComponent = char.VisibleString() + + class GeneralStringDecoder(OctetStringDecoder): protoComponent = char.GeneralString() + + class UniversalStringDecoder(OctetStringDecoder): protoComponent = char.UniversalString() + + class BMPStringDecoder(OctetStringDecoder): protoComponent = char.BMPString() + # "useful" types +class ObjectDescriptorDecoder(OctetStringDecoder): + protoComponent = useful.ObjectDescriptor() + + class GeneralizedTimeDecoder(OctetStringDecoder): protoComponent = useful.GeneralizedTime() + + class UTCTimeDecoder(OctetStringDecoder): protoComponent = useful.UTCTime() + tagMap = { - eoo.endOfOctets.tagSet: EndOfOctetsDecoder(), univ.Integer.tagSet: IntegerDecoder(), univ.Boolean.tagSet: BooleanDecoder(), univ.BitString.tagSet: BitStringDecoder(), @@ -536,9 +859,9 @@ tagMap = { univ.ObjectIdentifier.tagSet: ObjectIdentifierDecoder(), univ.Enumerated.tagSet: IntegerDecoder(), univ.Real.tagSet: RealDecoder(), - univ.Sequence.tagSet: SequenceDecoder(), # conflicts with SequenceOf - univ.Set.tagSet: SetDecoder(), # conflicts with SetOf - univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any + univ.Sequence.tagSet: SequenceOrSequenceOfDecoder(), # conflicts with SequenceOf + univ.Set.tagSet: SetOrSetOfDecoder(), # conflicts with SetOf + univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any # character string types char.UTF8String.tagSet: UTF8StringDecoder(), char.NumericString.tagSet: NumericStringDecoder(), @@ -552,9 +875,10 @@ tagMap = { char.UniversalString.tagSet: UniversalStringDecoder(), char.BMPString.tagSet: BMPStringDecoder(), # useful types + useful.ObjectDescriptor.tagSet: ObjectDescriptorDecoder(), useful.GeneralizedTime.tagSet: GeneralizedTimeDecoder(), useful.UTCTime.tagSet: UTCTimeDecoder() - } +} # Type-to-codec map for ambiguous ASN.1 types typeMap = { @@ -564,115 +888,169 @@ typeMap = { univ.SequenceOf.typeId: SequenceOfDecoder(), univ.Choice.typeId: ChoiceDecoder(), univ.Any.typeId: AnyDecoder() - } +} -( stDecodeTag, stDecodeLength, stGetValueDecoder, stGetValueDecoderByAsn1Spec, - stGetValueDecoderByTag, stTryAsExplicitTag, stDecodeValue, - stDumpRawValue, stErrorCondition, stStop ) = [x for x in range(10)] +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in tagMap.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in typeMap: + typeMap[typeId] = typeDecoder -class Decoder: + +(stDecodeTag, + stDecodeLength, + stGetValueDecoder, + stGetValueDecoderByAsn1Spec, + stGetValueDecoderByTag, + stTryAsExplicitTag, + stDecodeValue, + stDumpRawValue, + stErrorCondition, + stStop) = [x for x in range(10)] + + +class Decoder(object): defaultErrorState = stErrorCondition -# defaultErrorState = stDumpRawValue + # defaultErrorState = stDumpRawValue defaultRawDecoder = AnyDecoder() + supportIndefLength = True + + # noinspection PyDefaultArgument def __init__(self, tagMap, typeMap={}): self.__tagMap = tagMap self.__typeMap = typeMap - self.__endOfOctetsTagSet = eoo.endOfOctets.getTagSet() # Tag & TagSet objects caches self.__tagCache = {} self.__tagSetCache = {} - - def __call__(self, substrate, asn1Spec=None, tagSet=None, - length=None, state=stDecodeTag, recursiveFlag=1, - substrateFun=None): + self.__eooSentinel = ints2octs((0, 0)) + + def __call__(self, substrate, asn1Spec=None, + tagSet=None, length=None, state=stDecodeTag, + decodeFun=None, substrateFun=None, + **options): + if debug.logger & debug.flagDecoder: - debug.logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) + logger = debug.logger + else: + logger = None + + if logger: + logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) + + allowEoo = options.pop('allowEoo', False) + + # Look for end-of-octets sentinel + if allowEoo and self.supportIndefLength: + if substrate[:2] == self.__eooSentinel: + if logger: + logger('end-of-octets sentinel found') + return eoo.endOfOctets, substrate[2:] + + value = noValue + + tagMap = self.__tagMap + typeMap = self.__typeMap + tagCache = self.__tagCache + tagSetCache = self.__tagSetCache + fullSubstrate = substrate - while state != stStop: - if state == stDecodeTag: - # Decode tag + + while state is not stStop: + if state is stDecodeTag: if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on tag decoding' - ) - if not isOctetsType(substrate) and \ - not isinstance(substrate, univ.OctetString): - raise error.PyAsn1Error('Bad octet stream type') - + ) + # Decode tag + isShortTag = True firstOctet = substrate[0] substrate = substrate[1:] - if firstOctet in self.__tagCache: - lastTag = self.__tagCache[firstOctet] - else: - t = oct2int(firstOctet) - tagClass = t&0xC0 - tagFormat = t&0x20 - tagId = t&0x1F + try: + lastTag = tagCache[firstOctet] + except KeyError: + integerTag = oct2int(firstOctet) + tagClass = integerTag & 0xC0 + tagFormat = integerTag & 0x20 + tagId = integerTag & 0x1F if tagId == 0x1F: + isShortTag = False + lengthOctetIdx = 0 tagId = 0 - while 1: - if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on long tag decoding' - ) - t = oct2int(substrate[0]) - tagId = tagId << 7 | (t&0x7F) - substrate = substrate[1:] - if not t&0x80: - break + try: + while True: + integerTag = oct2int(substrate[lengthOctetIdx]) + lengthOctetIdx += 1 + tagId <<= 7 + tagId |= (integerTag & 0x7F) + if not integerTag & 0x80: + break + substrate = substrate[lengthOctetIdx:] + except IndexError: + raise error.SubstrateUnderrunError( + 'Short octet stream on long tag decoding' + ) lastTag = tag.Tag( tagClass=tagClass, tagFormat=tagFormat, tagId=tagId - ) - if tagId < 31: + ) + if isShortTag: # cache short tags - self.__tagCache[firstOctet] = lastTag + tagCache[firstOctet] = lastTag if tagSet is None: - if firstOctet in self.__tagSetCache: - tagSet = self.__tagSetCache[firstOctet] + if isShortTag: + try: + tagSet = tagSetCache[firstOctet] + except KeyError: + # base tag not recovered + tagSet = tag.TagSet((), lastTag) + tagSetCache[firstOctet] = tagSet else: - # base tag not recovered tagSet = tag.TagSet((), lastTag) - if firstOctet in self.__tagCache: - self.__tagSetCache[firstOctet] = tagSet else: tagSet = lastTag + tagSet state = stDecodeLength - debug.logger and debug.logger & debug.flagDecoder and debug.logger('tag decoded into %r, decoding length' % tagSet) - if state == stDecodeLength: + if logger: + logger('tag decoded into %s, decoding length' % tagSet) + if state is stDecodeLength: # Decode length if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on length decoding' - ) - firstOctet = oct2int(substrate[0]) - if firstOctet == 128: + raise error.SubstrateUnderrunError( + 'Short octet stream on length decoding' + ) + firstOctet = oct2int(substrate[0]) + if firstOctet < 128: size = 1 - length = -1 - elif firstOctet < 128: - length, size = firstOctet, 1 - else: + length = firstOctet + elif firstOctet > 128: size = firstOctet & 0x7F # encoded in size bytes - length = 0 - lengthString = substrate[1:size+1] + encodedLength = octs2ints(substrate[1:size + 1]) # missing check on maximum size, which shouldn't be a # problem, we can handle more than is possible - if len(lengthString) != size: + if len(encodedLength) != size: raise error.SubstrateUnderrunError( - '%s<%s at %s' % - (size, len(lengthString), tagSet) - ) - for char in lengthString: - length = (length << 8) | oct2int(char) - size = size + 1 - substrate = substrate[size:] - if length != -1 and len(substrate) < length: - raise error.SubstrateUnderrunError( - '%d-octet short' % (length - len(substrate)) + '%s<%s at %s' % (size, len(encodedLength), tagSet) ) + length = 0 + for lengthOctet in encodedLength: + length <<= 8 + length |= lengthOctet + size += 1 + else: + size = 1 + length = -1 + + substrate = substrate[size:] + if length == -1: + if not self.supportIndefLength: + raise error.PyAsn1Error('Indefinite length encoding not supported by this codec') + else: + if len(substrate) < length: + raise error.SubstrateUnderrunError('%d-octet short' % (length - len(substrate))) state = stGetValueDecoder - debug.logger and debug.logger & debug.flagDecoder and debug.logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length]))) - if state == stGetValueDecoder: + if logger: + logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length]))) + if state is stGetValueDecoder: if asn1Spec is None: state = stGetValueDecoderByTag else: @@ -692,116 +1070,150 @@ class Decoder: # in an incremental, tag-by-tag fashion (this is the case of # EXPLICIT tag which is most basic). Outermost tag comes first # from the wire. - # - if state == stGetValueDecoderByTag: - if tagSet in self.__tagMap: - concreteDecoder = self.__tagMap[tagSet] - else: + # + if state is stGetValueDecoderByTag: + try: + concreteDecoder = tagMap[tagSet] + except KeyError: concreteDecoder = None if concreteDecoder: state = stDecodeValue else: - _k = tagSet[:1] - if _k in self.__tagMap: - concreteDecoder = self.__tagMap[_k] - else: + try: + concreteDecoder = tagMap[tagSet[:1]] + except KeyError: concreteDecoder = None if concreteDecoder: state = stDecodeValue else: state = stTryAsExplicitTag - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as explicit tag')) + if logger: + logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as explicit tag')) debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) - if state == stGetValueDecoderByAsn1Spec: - if isinstance(asn1Spec, (dict, tagmap.TagMap)): - if tagSet in asn1Spec: - __chosenSpec = asn1Spec[tagSet] - else: - __chosenSpec = None - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('candidate ASN.1 spec is a map of:') - for t, v in asn1Spec.getPosMap().items(): - debug.logger(' %r -> %s' % (t, v.__class__.__name__)) - if asn1Spec.getNegMap(): - debug.logger('but neither of: ') - for i in asn1Spec.getNegMap().items(): - debug.logger(' %r -> %s' % (t, v.__class__.__name__)) - debug.logger('new candidate ASN.1 spec is %s, chosen by %r' % (__chosenSpec is None and '' or __chosenSpec.__class__.__name__, tagSet)) + if state is stGetValueDecoderByAsn1Spec: + if asn1Spec.__class__ is tagmap.TagMap: + try: + chosenSpec = asn1Spec[tagSet] + except KeyError: + chosenSpec = None + if logger: + logger('candidate ASN.1 spec is a map of:') + for firstOctet, v in asn1Spec.presentTypes.items(): + logger(' %s -> %s' % (firstOctet, v.__class__.__name__)) + if asn1Spec.skipTypes: + logger('but neither of: ') + for firstOctet, v in asn1Spec.skipTypes.items(): + logger(' %s -> %s' % (firstOctet, v.__class__.__name__)) + logger('new candidate ASN.1 spec is %s, chosen by %s' % (chosenSpec is None and '' or chosenSpec.prettyPrintType(), tagSet)) + elif tagSet == asn1Spec.tagSet or tagSet in asn1Spec.tagMap: + chosenSpec = asn1Spec + if logger: + logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) else: - __chosenSpec = asn1Spec - debug.logger and debug.logger & debug.flagDecoder and debug.logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) - if __chosenSpec is not None and ( - tagSet == __chosenSpec.getTagSet() or \ - tagSet in __chosenSpec.getTagMap() - ): - # use base type for codec lookup to recover untagged types - baseTagSet = __chosenSpec.baseTagSet - if __chosenSpec.typeId is not None and \ - __chosenSpec.typeId in self.__typeMap: - # ambiguous type - concreteDecoder = self.__typeMap[__chosenSpec.typeId] - debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId,)) - elif baseTagSet in self.__tagMap: - # base type or tagged subtype - concreteDecoder = self.__tagMap[baseTagSet] - debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base %r' % (baseTagSet,)) - else: - concreteDecoder = None + chosenSpec = None + + if chosenSpec is not None: + try: + # ambiguous type or just faster codec lookup + concreteDecoder = typeMap[chosenSpec.typeId] + if logger: + logger('value decoder chosen for an ambiguous type by type ID %s' % (chosenSpec.typeId,)) + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(chosenSpec.tagSet.baseTag, chosenSpec.tagSet.baseTag) + try: + # base type or tagged subtype + concreteDecoder = tagMap[baseTagSet] + if logger: + logger('value decoder chosen by base %s' % (baseTagSet,)) + except KeyError: + concreteDecoder = None if concreteDecoder: - asn1Spec = __chosenSpec + asn1Spec = chosenSpec state = stDecodeValue else: state = stTryAsExplicitTag - elif tagSet == self.__endOfOctetsTagSet: - concreteDecoder = self.__tagMap[tagSet] - state = stDecodeValue - debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets found') else: concreteDecoder = None state = stTryAsExplicitTag - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as explicit tag')) - debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__) - if state == stTryAsExplicitTag: - if tagSet and \ - tagSet[0][1] == tag.tagFormatConstructed and \ - tagSet[0][0] != tag.tagClassUniversal: + if logger: + logger('codec %s chosen by ASN.1 spec, decoding %s' % (state is stDecodeValue and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as explicit tag')) + debug.scope.push(chosenSpec is None and '?' or chosenSpec.__class__.__name__) + if state is stDecodeValue: + if not options.get('recursiveFlag', True) and not substrateFun: # deprecate this + substrateFun = lambda a, b, c: (a, b[:c]) + + options.update(fullSubstrate=fullSubstrate) + + if length == -1: # indef length + value, substrate = concreteDecoder.indefLenValueDecoder( + substrate, asn1Spec, + tagSet, length, stGetValueDecoder, + self, substrateFun, + **options + ) + else: + value, substrate = concreteDecoder.valueDecoder( + substrate, asn1Spec, + tagSet, length, stGetValueDecoder, + self, substrateFun, + **options + ) + if logger: + logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, isinstance(value, base.Asn1Item) and value.prettyPrint() or value, substrate and debug.hexdump(substrate) or '')) + state = stStop + break + if state is stTryAsExplicitTag: + if tagSet and tagSet[0].tagFormat == tag.tagFormatConstructed and tagSet[0].tagClass != tag.tagClassUniversal: # Assume explicit tagging concreteDecoder = explicitTagDecoder state = stDecodeValue - else: + else: concreteDecoder = None state = self.defaultErrorState - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as failure')) - if state == stDumpRawValue: + if logger: + logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as failure')) + if state is stDumpRawValue: concreteDecoder = self.defaultRawDecoder - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) + if logger: + logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) state = stDecodeValue - if state == stDecodeValue: - if recursiveFlag == 0 and not substrateFun: # legacy - substrateFun = lambda a,b,c: (a,b[:c]) - if length == -1: # indef length - value, substrate = concreteDecoder.indefLenValueDecoder( - fullSubstrate, substrate, asn1Spec, tagSet, length, - stGetValueDecoder, self, substrateFun - ) - else: - value, substrate = concreteDecoder.valueDecoder( - fullSubstrate, substrate, asn1Spec, tagSet, length, - stGetValueDecoder, self, substrateFun - ) - state = stStop - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '')) - if state == stErrorCondition: + if state is stErrorCondition: raise error.PyAsn1Error( - '%r not in asn1Spec: %r' % (tagSet, asn1Spec) - ) - if debug.logger and debug.logger & debug.flagDecoder: + '%s not in asn1Spec: %r' % (tagSet, asn1Spec) + ) + if logger: debug.scope.pop() - debug.logger('decoder left scope %s, call completed' % debug.scope) + logger('decoder left scope %s, call completed' % debug.scope) return value, substrate - + + +#: Turns BER octet stream into an ASN.1 object. +#: +#: Takes BER octetstream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: BER octetstream +#: +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from BER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On decoding errors decode = Decoder(tagMap, typeMap) # XXX diff --git a/third_party/python/pyasn1/pyasn1/codec/ber/encoder.py b/third_party/python/pyasn1/pyasn1/codec/ber/encoder.py index 173949d0b68b..4ed4c3b7fb71 100644 --- a/third_party/python/pyasn1/pyasn1/codec/ber/encoder.py +++ b/third_party/python/pyasn1/pyasn1/codec/ber/encoder.py @@ -1,229 +1,344 @@ -# BER encoder -from pyasn1.type import base, tag, univ, char, useful +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from pyasn1.type import tag, univ, char, useful from pyasn1.codec.ber import eoo from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs +from pyasn1.compat.integer import to_bytes from pyasn1 import debug, error -class Error(Exception): pass +__all__ = ['encode'] -class AbstractItemEncoder: + +class AbstractItemEncoder(object): supportIndefLenMode = 1 - def encodeTag(self, t, isConstructed): - tagClass, tagFormat, tagId = t.asTuple() # this is a hotspot - v = tagClass | tagFormat + + # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)` + eooIntegerSubstrate = (0, 0) + eooOctetsSubstrate = ints2octs(eooIntegerSubstrate) + + # noinspection PyMethodMayBeStatic + def encodeTag(self, singleTag, isConstructed): + tagClass, tagFormat, tagId = singleTag + encodedTag = tagClass | tagFormat if isConstructed: - v = v|tag.tagFormatConstructed + encodedTag |= tag.tagFormatConstructed if tagId < 31: - return int2oct(v|tagId) + return encodedTag | tagId, else: - s = int2oct(tagId&0x7f) - tagId = tagId >> 7 + substrate = tagId & 0x7f, + tagId >>= 7 while tagId: - s = int2oct(0x80|(tagId&0x7f)) + s - tagId = tagId >> 7 - return int2oct(v|0x1F) + s + substrate = (0x80 | (tagId & 0x7f),) + substrate + tagId >>= 7 + return (encodedTag | 0x1F,) + substrate def encodeLength(self, length, defMode): if not defMode and self.supportIndefLenMode: - return int2oct(0x80) + return (0x80,) if length < 0x80: - return int2oct(length) + return length, else: - substrate = null + substrate = () while length: - substrate = int2oct(length&0xff) + substrate - length = length >> 8 + substrate = (length & 0xff,) + substrate + length >>= 8 substrateLen = len(substrate) if substrateLen > 126: - raise Error('Length octets overflow (%d)' % substrateLen) - return int2oct(0x80 | substrateLen) + substrate + raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen) + return (0x80 | substrateLen,) + substrate - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - raise Error('Not implemented') + def encodeValue(self, value, encodeFun, **options): + raise error.PyAsn1Error('Not implemented') - def _encodeEndOfOctets(self, encodeFun, defMode): - if defMode or not self.supportIndefLenMode: - return null - else: - return encodeFun(eoo.endOfOctets, defMode) - - def encode(self, encodeFun, value, defMode, maxChunkSize): - substrate, isConstructed = self.encodeValue( - encodeFun, value, defMode, maxChunkSize + def encode(self, value, encodeFun, **options): + + tagSet = value.tagSet + + # untagged item? + if not tagSet: + substrate, isConstructed, isOctets = self.encodeValue( + value, encodeFun, **options ) - tagSet = value.getTagSet() - if tagSet: - if not isConstructed: # primitive form implies definite mode - defMode = 1 - return self.encodeTag( - tagSet[-1], isConstructed - ) + self.encodeLength( - len(substrate), defMode - ) + substrate + self._encodeEndOfOctets(encodeFun, defMode) - else: - return substrate # untagged value + return substrate + + defMode = options.get('defMode', True) + + for idx, singleTag in enumerate(tagSet.superTags): + + defModeOverride = defMode + + # base tag? + if not idx: + substrate, isConstructed, isOctets = self.encodeValue( + value, encodeFun, **options + ) + + if options.get('ifNotEmpty', False) and not substrate: + return substrate + + # primitive form implies definite mode + if not isConstructed: + defModeOverride = True + + header = self.encodeTag(singleTag, isConstructed) + header += self.encodeLength(len(substrate), defModeOverride) + + if isOctets: + substrate = ints2octs(header) + substrate + + if not defModeOverride: + substrate += self.eooOctetsSubstrate + + else: + substrate = header + substrate + + if not defModeOverride: + substrate += self.eooIntegerSubstrate + + if not isOctets: + substrate = ints2octs(substrate) + + return substrate + class EndOfOctetsEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return null, 0 + def encodeValue(self, value, encodeFun, **options): + return null, False, True -class ExplicitlyTaggedItemEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if isinstance(value, base.AbstractConstructedAsn1Item): - value = value.clone(tagSet=value.getTagSet()[:-1], - cloneValueFlag=1) - else: - value = value.clone(tagSet=value.getTagSet()[:-1]) - return encodeFun(value, defMode, maxChunkSize), 1 - -explicitlyTaggedItemEncoder = ExplicitlyTaggedItemEncoder() class BooleanEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - _true = ints2octs((1,)) - _false = ints2octs((0,)) - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return value and self._true or self._false, 0 + supportIndefLenMode = False + + def encodeValue(self, value, encodeFun, **options): + return value and (1,) or (0,), False, False + class IntegerEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 + supportIndefLenMode = False supportCompactZero = False - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if value == 0: # shortcut for zero value + + def encodeValue(self, value, encodeFun, **options): + if value == 0: + # de-facto way to encode zero if self.supportCompactZero: - # this seems to be a correct way for encoding zeros - return null, 0 + return (), False, False else: - # this seems to be a widespread way for encoding zeros - return ints2octs((0,)), 0 - octets = [] - value = int(value) # to save on ops on asn1 type - while 1: - octets.insert(0, value & 0xff) - if value == 0 or value == -1: - break - value = value >> 8 - if value == 0 and octets[0] & 0x80: - octets.insert(0, 0) - while len(octets) > 1 and \ - (octets[0] == 0 and octets[1] & 0x80 == 0 or \ - octets[0] == 0xff and octets[1] & 0x80 != 0): - del octets[0] - return ints2octs(octets), 0 + return (0,), False, False + + return to_bytes(int(value), signed=True), False, True + class BitStringEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if not maxChunkSize or len(value) <= maxChunkSize*8: - r = {}; l = len(value); p = 0; j = 7 - while p < l: - i, j = divmod(p, 8) - r[i] = r.get(i,0) | value[p]<<(7-j) - p = p + 1 - keys = list(r); keys.sort() - return int2oct(7-j) + ints2octs([r[k] for k in keys]), 0 + def encodeValue(self, value, encodeFun, **options): + valueLength = len(value) + if valueLength % 8: + alignedValue = value << (8 - valueLength % 8) else: - pos = 0; substrate = null - while 1: - # count in octets - v = value.clone(value[pos*8:pos*8+maxChunkSize*8]) - if not v: - break - substrate = substrate + encodeFun(v, defMode, maxChunkSize) - pos = pos + maxChunkSize - return substrate, 1 + alignedValue = value + + maxChunkSize = options.get('maxChunkSize', 0) + if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8: + substrate = alignedValue.asOctets() + return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True + + # strip off explicit tags + alignedValue = alignedValue.clone( + tagSet=tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) + ) + + stop = 0 + substrate = null + while stop < valueLength: + start = stop + stop = min(start + maxChunkSize * 8, valueLength) + substrate += encodeFun(alignedValue[start:stop], **options) + + return substrate, True, True + class OctetStringEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): + def encodeValue(self, value, encodeFun, **options): + maxChunkSize = options.get('maxChunkSize', 0) if not maxChunkSize or len(value) <= maxChunkSize: - return value.asOctets(), 0 + return value.asOctets(), False, True + else: - pos = 0; substrate = null - while 1: - v = value.clone(value[pos:pos+maxChunkSize]) - if not v: + # will strip off explicit tags + baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) + + pos = 0 + substrate = null + while True: + chunk = value.clone(value[pos:pos + maxChunkSize], + tagSet=baseTagSet) + if not chunk: break - substrate = substrate + encodeFun(v, defMode, maxChunkSize) - pos = pos + maxChunkSize - return substrate, 1 + substrate += encodeFun(chunk, **options) + pos += maxChunkSize + + return substrate, True, True + class NullEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return null, 0 + supportIndefLenMode = False + + def encodeValue(self, value, encodeFun, **options): + return null, False, True + class ObjectIdentifierEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - precomputedValues = { - (1, 3, 6, 1, 2): (43, 6, 1, 2), - (1, 3, 6, 1, 4): (43, 6, 1, 4) - } - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): + supportIndefLenMode = False + + def encodeValue(self, value, encodeFun, **options): oid = value.asTuple() - if oid[:5] in self.precomputedValues: - octets = self.precomputedValues[oid[:5]] - index = 5 - else: - if len(oid) < 2: - raise error.PyAsn1Error('Short OID %s' % (value,)) - # Build the first twos - if oid[0] > 6 or oid[1] > 39 or oid[0] == 6 and oid[1] > 15: - raise error.PyAsn1Error( - 'Initial sub-ID overflow %s in OID %s' % (oid[:2], value) - ) - octets = (oid[0] * 40 + oid[1],) - index = 2 + # Build the first pair + try: + first = oid[0] + second = oid[1] - # Cycle through subids - for subid in oid[index:]: - if subid > -1 and subid < 128: - # Optimize for the common case - octets = octets + (subid & 0x7f,) - elif subid < 0 or subid > 0xFFFFFFFF: - raise error.PyAsn1Error( - 'SubId overflow %s in %s' % (subid, value) - ) + except IndexError: + raise error.PyAsn1Error('Short OID %s' % (value,)) + + if 0 <= second <= 39: + if first == 1: + oid = (second + 40,) + oid[2:] + elif first == 0: + oid = (second,) + oid[2:] + elif first == 2: + oid = (second + 80,) + oid[2:] else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + elif first == 2: + oid = (second + 80,) + oid[2:] + else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + + octets = () + + # Cycle through subIds + for subOid in oid: + if 0 <= subOid <= 127: + # Optimize for the common case + octets += (subOid,) + elif subOid > 127: # Pack large Sub-Object IDs - res = (subid & 0x7f,) - subid = subid >> 7 - while subid > 0: - res = (0x80 | (subid & 0x7f),) + res - subid = subid >> 7 + res = (subOid & 0x7f,) + subOid >>= 7 + while subOid: + res = (0x80 | (subOid & 0x7f),) + res + subOid >>= 7 # Add packed Sub-Object ID to resulted Object ID octets += res - - return ints2octs(octets), 0 + else: + raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value)) + + return octets, False, False + class RealEncoder(AbstractItemEncoder): supportIndefLenMode = 0 - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if value.isPlusInfinity(): - return int2oct(0x40), 0 - if value.isMinusInfinity(): - return int2oct(0x41), 0 + binEncBase = 2 # set to None to choose encoding base automatically + + @staticmethod + def _dropFloatingPoint(m, encbase, e): + ms, es = 1, 1 + if m < 0: + ms = -1 # mantissa sign + if e < 0: + es = -1 # exponenta sign + m *= ms + if encbase == 8: + m *= 2 ** (abs(e) % 3 * es) + e = abs(e) // 3 * es + elif encbase == 16: + m *= 2 ** (abs(e) % 4 * es) + e = abs(e) // 4 * es + + while True: + if int(m) != m: + m *= encbase + e -= 1 + continue + break + return ms, int(m), encbase, e + + def _chooseEncBase(self, value): + m, b, e = value + encBase = [2, 8, 16] + if value.binEncBase in encBase: + return self._dropFloatingPoint(m, value.binEncBase, e) + elif self.binEncBase in encBase: + return self._dropFloatingPoint(m, self.binEncBase, e) + # auto choosing base 2/8/16 + mantissa = [m, m, m] + exponenta = [e, e, e] + sign = 1 + encbase = 2 + e = float('inf') + for i in range(3): + (sign, + mantissa[i], + encBase[i], + exponenta[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponenta[i]) + if abs(exponenta[i]) < abs(e) or (abs(exponenta[i]) == abs(e) and mantissa[i] < m): + e = exponenta[i] + m = int(mantissa[i]) + encbase = encBase[i] + return sign, m, encbase, e + + def encodeValue(self, value, encodeFun, **options): + if value.isPlusInf: + return (0x40,), False, False + if value.isMinusInf: + return (0x41,), False, False m, b, e = value if not m: - return null, 0 + return null, False, True if b == 10: - return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), 0 + return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True elif b == 2: - fo = 0x80 # binary enoding - if m < 0: - fo = fo | 0x40 # sign bit - m = -m - while int(m) != m: # drop floating point - m *= 2 - e -= 1 - while m & 0x1 == 0: # mantissa normalization + fo = 0x80 # binary encoding + ms, m, encbase, e = self._chooseEncBase(value) + if ms < 0: # mantissa sign + fo |= 0x40 # sign bit + # exponenta & mantissa normalization + if encbase == 2: + while m & 0x1 == 0: + m >>= 1 + e += 1 + elif encbase == 8: + while m & 0x7 == 0: + m >>= 3 + e += 1 + fo |= 0x10 + else: # encbase = 16 + while m & 0xf == 0: + m >>= 4 + e += 1 + fo |= 0x20 + sf = 0 # scale factor + while m & 0x1 == 0: m >>= 1 - e += 1 + sf += 1 + if sf > 3: + raise error.PyAsn1Error('Scale factor overflow') # bug if raised + fo |= sf << 2 eo = null - while e not in (0, -1): - eo = int2oct(e&0xff) + eo - e >>= 8 - if e == 0 and eo and oct2int(eo[0]) & 0x80: - eo = int2oct(0) + eo + if e == 0 or e == -1: + eo = int2oct(e & 0xff) + else: + while e not in (0, -1): + eo = int2oct(e & 0xff) + eo + e >>= 8 + if e == 0 and eo and oct2int(eo[0]) & 0x80: + eo = int2oct(0) + eo + if e == -1 and eo and not (oct2int(eo[0]) & 0x80): + eo = int2oct(0xff) + eo n = len(eo) if n > 0xff: raise error.PyAsn1Error('Real exponent overflow') @@ -235,51 +350,57 @@ class RealEncoder(AbstractItemEncoder): fo |= 2 else: fo |= 3 - eo = int2oct(n//0xff+1) + eo + eo = int2oct(n & 0xff) + eo po = null while m: - po = int2oct(m&0xff) + po + po = int2oct(m & 0xff) + po m >>= 8 substrate = int2oct(fo) + eo + po - return substrate, 0 + return substrate, False, True else: raise error.PyAsn1Error('Prohibited Real base %s' % b) + class SequenceEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - value.setDefaultComponents() + def encodeValue(self, value, encodeFun, **options): value.verifySizeSpec() - substrate = null; idx = len(value) + + namedTypes = value.componentType + substrate = null + + idx = len(value) while idx > 0: - idx = idx - 1 - if value[idx] is None: # Optional component - continue - component = value.getDefaultComponentByPosition(idx) - if component is not None and component == value[idx]: - continue - substrate = encodeFun( - value[idx], defMode, maxChunkSize - ) + substrate - return substrate, 1 + idx -= 1 + if namedTypes: + if namedTypes[idx].isOptional and not value[idx].isValue: + continue + if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object: + continue + substrate = encodeFun(value[idx], **options) + substrate + + return substrate, True, True + class SequenceOfEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): + def encodeValue(self, value, encodeFun, **options): value.verifySizeSpec() - substrate = null; idx = len(value) + substrate = null + idx = len(value) while idx > 0: - idx = idx - 1 - substrate = encodeFun( - value[idx], defMode, maxChunkSize - ) + substrate - return substrate, 1 + idx -= 1 + substrate = encodeFun(value[idx], **options) + substrate + return substrate, True, True + class ChoiceEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return encodeFun(value.getComponent(), defMode, maxChunkSize), 1 + def encodeValue(self, value, encodeFun, **options): + return encodeFun(value.getComponent(), **options), True, True + class AnyEncoder(OctetStringEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return value.asOctets(), defMode == 0 + def encodeValue(self, value, encodeFun, **options): + return value.asOctets(), not options.get('defMode', True), True + tagMap = { eoo.endOfOctets.tagSet: EndOfOctetsEncoder(), @@ -308,46 +429,120 @@ tagMap = { char.UniversalString.tagSet: OctetStringEncoder(), char.BMPString.tagSet: OctetStringEncoder(), # useful types + useful.ObjectDescriptor.tagSet: OctetStringEncoder(), useful.GeneralizedTime.tagSet: OctetStringEncoder(), - useful.UTCTime.tagSet: OctetStringEncoder() - } + useful.UTCTime.tagSet: OctetStringEncoder() +} -# Type-to-codec map for ambiguous ASN.1 types +# Put in ambiguous & non-ambiguous types for faster codec lookup typeMap = { + univ.Boolean.typeId: BooleanEncoder(), + univ.Integer.typeId: IntegerEncoder(), + univ.BitString.typeId: BitStringEncoder(), + univ.OctetString.typeId: OctetStringEncoder(), + univ.Null.typeId: NullEncoder(), + univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), + univ.Enumerated.typeId: IntegerEncoder(), + univ.Real.typeId: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf univ.Set.typeId: SequenceEncoder(), univ.SetOf.typeId: SequenceOfEncoder(), univ.Sequence.typeId: SequenceEncoder(), univ.SequenceOf.typeId: SequenceOfEncoder(), univ.Choice.typeId: ChoiceEncoder(), - univ.Any.typeId: AnyEncoder() - } + univ.Any.typeId: AnyEncoder(), + # character string types + char.UTF8String.typeId: OctetStringEncoder(), + char.NumericString.typeId: OctetStringEncoder(), + char.PrintableString.typeId: OctetStringEncoder(), + char.TeletexString.typeId: OctetStringEncoder(), + char.VideotexString.typeId: OctetStringEncoder(), + char.IA5String.typeId: OctetStringEncoder(), + char.GraphicString.typeId: OctetStringEncoder(), + char.VisibleString.typeId: OctetStringEncoder(), + char.GeneralString.typeId: OctetStringEncoder(), + char.UniversalString.typeId: OctetStringEncoder(), + char.BMPString.typeId: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.typeId: OctetStringEncoder(), + useful.GeneralizedTime.typeId: OctetStringEncoder(), + useful.UTCTime.typeId: OctetStringEncoder() +} -class Encoder: + +class Encoder(object): + fixedDefLengthMode = None + fixedChunkSize = None + + # noinspection PyDefaultArgument def __init__(self, tagMap, typeMap={}): self.__tagMap = tagMap self.__typeMap = typeMap - def __call__(self, value, defMode=1, maxChunkSize=0): - debug.logger & debug.flagEncoder and debug.logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not defMode and 'in' or '', maxChunkSize, value.__class__.__name__, value.prettyPrint())) - tagSet = value.getTagSet() - if len(tagSet) > 1: - concreteEncoder = explicitlyTaggedItemEncoder + def __call__(self, value, **options): + + if debug.logger & debug.flagEncoder: + logger = debug.logger else: - if value.typeId is not None and value.typeId in self.__typeMap: - concreteEncoder = self.__typeMap[value.typeId] - elif tagSet in self.__tagMap: - concreteEncoder = self.__tagMap[tagSet] - else: - tagSet = value.baseTagSet - if tagSet in self.__tagMap: - concreteEncoder = self.__tagMap[tagSet] - else: - raise Error('No encoder for %s' % (value,)) - debug.logger & debug.flagEncoder and debug.logger('using value codec %s chosen by %r' % (concreteEncoder.__class__.__name__, tagSet)) - substrate = concreteEncoder.encode( - self, value, defMode, maxChunkSize - ) - debug.logger & debug.flagEncoder and debug.logger('built %s octets of substrate: %s\nencoder completed' % (len(substrate), debug.hexdump(substrate))) + logger = None + + if logger: + logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), value.prettyPrintType(), value.prettyPrint())) + + if self.fixedDefLengthMode is not None: + options.update(defMode=self.fixedDefLengthMode) + + if self.fixedChunkSize is not None: + options.update(maxChunkSize=self.fixedChunkSize) + + tagSet = value.tagSet + + try: + concreteEncoder = self.__typeMap[value.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) + + try: + concreteEncoder = self.__tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('No encoder for %s' % (value,)) + + if logger: + logger('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) + + substrate = concreteEncoder.encode(value, self, **options) + + if logger: + logger('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate))) + return substrate +#: Turns ASN.1 object into BER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a BER octet stream. +#: +#: Parameters +#: ---------- +# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A pyasn1 object to encode +#: +#: 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) +#: Given ASN.1 object encoded into BER octetstream +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On encoding errors encode = Encoder(tagMap, typeMap) diff --git a/third_party/python/pyasn1/pyasn1/codec/ber/eoo.py b/third_party/python/pyasn1/pyasn1/codec/ber/eoo.py index 379be199659c..28e33c5ac8f5 100644 --- a/third_party/python/pyasn1/pyasn1/codec/ber/eoo.py +++ b/third_party/python/pyasn1/pyasn1/codec/ber/eoo.py @@ -1,8 +1,25 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1.type import base, tag + class EndOfOctets(base.AbstractSimpleAsn1Item): defaultValue = 0 tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00) - ) + ) + + _instance = None + + def __new__(cls, *args, **kwargs): + if cls._instance is None: + cls._instance = object.__new__(cls, *args, **kwargs) + + return cls._instance + + endOfOctets = EndOfOctets() diff --git a/third_party/python/pyasn1/pyasn1/codec/cer/decoder.py b/third_party/python/pyasn1/pyasn1/codec/cer/decoder.py index 9fd37c134739..5e3e8bf246de 100644 --- a/third_party/python/pyasn1/pyasn1/codec/cer/decoder.py +++ b/third_party/python/pyasn1/pyasn1/codec/cer/decoder.py @@ -1,16 +1,27 @@ -# CER decoder +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1.type import univ from pyasn1.codec.ber import decoder from pyasn1.compat.octets import oct2int from pyasn1 import error +__all__ = ['decode'] + + class BooleanDecoder(decoder.AbstractSimpleDecoder): protoComponent = univ.Boolean(0) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): head, tail = substrate[:length], substrate[length:] - if not head: - raise error.PyAsn1Error('Empty substrate') + if not head or length != 1: + raise error.PyAsn1Error('Not single-octet Boolean payload') byte = oct2int(head[0]) # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 @@ -20,16 +31,60 @@ class BooleanDecoder(decoder.AbstractSimpleDecoder): elif byte == 0x00: value = 0 else: - raise error.PyAsn1Error('Boolean CER violation: %s' % byte) + raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) return self._createComponent(asn1Spec, tagSet, value), tail +# TODO: prohibit non-canonical encoding +BitStringDecoder = decoder.BitStringDecoder +OctetStringDecoder = decoder.OctetStringDecoder +RealDecoder = decoder.RealDecoder + tagMap = decoder.tagMap.copy() -tagMap.update({ - univ.Boolean.tagSet: BooleanDecoder() - }) +tagMap.update( + {univ.Boolean.tagSet: BooleanDecoder(), + univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: OctetStringDecoder(), + univ.Real.tagSet: RealDecoder()} +) -typeMap = decoder.typeMap +typeMap = decoder.typeMap.copy() -class Decoder(decoder.Decoder): pass +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in tagMap.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in typeMap: + typeMap[typeId] = typeDecoder + +class Decoder(decoder.Decoder): + pass + + +#: Turns CER octet stream into an ASN.1 object. +#: +#: Takes CER octetstream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: CER octetstream +#: +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On decoding errors decode = Decoder(tagMap, decoder.typeMap) diff --git a/third_party/python/pyasn1/pyasn1/codec/cer/encoder.py b/third_party/python/pyasn1/pyasn1/codec/cer/encoder.py index 4c05130af973..4700de0af106 100644 --- a/third_party/python/pyasn1/pyasn1/codec/cer/encoder.py +++ b/third_party/python/pyasn1/pyasn1/codec/cer/encoder.py @@ -1,87 +1,221 @@ -# CER encoder +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1.type import univ +from pyasn1.type import useful from pyasn1.codec.ber import encoder -from pyasn1.compat.octets import int2oct, null +from pyasn1.compat.octets import str2octs, null +from pyasn1 import error + +__all__ = ['encode'] + class BooleanEncoder(encoder.IntegerEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - if client == 0: - substrate = int2oct(0) + def encodeValue(self, value, encodeFun, **options): + if value == 0: + substrate = (0,) else: - substrate = int2oct(255) - return substrate, 0 + substrate = (255,) + return substrate, False, False -class BitStringEncoder(encoder.BitStringEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - return encoder.BitStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) -class OctetStringEncoder(encoder.OctetStringEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) +class RealEncoder(encoder.RealEncoder): + def _chooseEncBase(self, value): + m, b, e = value + return self._dropFloatingPoint(m, b, e) + -# specialized RealEncoder here # specialized GeneralStringEncoder here -# specialized GeneralizedTimeEncoder here -# specialized UTCTimeEncoder here + +class TimeEncoderMixIn(object): + zchar, = str2octs('Z') + pluschar, = str2octs('+') + minuschar, = str2octs('-') + commachar, = str2octs(',') + minLength = 12 + maxLength = 19 + + def encodeValue(self, value, encodeFun, **options): + # Encoding constraints: + # - minutes are mandatory, seconds are optional + # - subseconds must NOT be zero + # - no hanging fraction dot + # - time in UTC (Z) + # - only dot is allowed for fractions + + octets = value.asOctets() + + if not self.minLength < len(octets) < self.maxLength: + raise error.PyAsn1Error('Length constraint violated: %r' % value) + + if self.pluschar in octets or self.minuschar in octets: + raise error.PyAsn1Error('Must be UTC time: %r' % octets) + + if octets[-1] != self.zchar: + raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % octets) + + if self.commachar in octets: + raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value) + + options.update(maxChunkSize=1000) + + return encoder.OctetStringEncoder.encodeValue( + self, value, encodeFun, **options + ) + + +class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): + minLength = 12 + maxLength = 19 + + +class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): + minLength = 10 + maxLength = 14 + class SetOfEncoder(encoder.SequenceOfEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - if isinstance(client, univ.SequenceAndSetBase): - client.setDefaultComponents() - client.verifySizeSpec() - substrate = null; idx = len(client) - # This is certainly a hack but how else do I distinguish SetOf - # from Set if they have the same tags&constraints? - if isinstance(client, univ.SequenceAndSetBase): - # Set + @staticmethod + def _sortComponents(components): + # sort by tags regardless of the Choice value (static sort) + return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.minTagSet or x.tagSet) + + def encodeValue(self, value, encodeFun, **options): + value.verifySizeSpec() + substrate = null + idx = len(value) + if value.typeId == univ.Set.typeId: + namedTypes = value.componentType comps = [] + compsMap = {} while idx > 0: - idx = idx - 1 - if client[idx] is None: # Optional component - continue - if client.getDefaultComponentByPosition(idx) == client[idx]: - continue - comps.append(client[idx]) - comps.sort(key=lambda x: isinstance(x, univ.Choice) and \ - x.getMinTagSet() or x.getTagSet()) - for c in comps: - substrate += encodeFun(c, defMode, maxChunkSize) + idx -= 1 + if namedTypes: + if namedTypes[idx].isOptional and not value[idx].isValue: + continue + if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object: + continue + + comps.append(value[idx]) + compsMap[id(value[idx])] = namedTypes and namedTypes[idx].isOptional + + for comp in self._sortComponents(comps): + options.update(ifNotEmpty=compsMap[id(comp)]) + substrate += encodeFun(comp, **options) else: - # SetOf - compSubs = [] - while idx > 0: - idx = idx - 1 - compSubs.append( - encodeFun(client[idx], defMode, maxChunkSize) - ) - compSubs.sort() # perhaps padding's not needed - substrate = null - for compSub in compSubs: - substrate += compSub - return substrate, 1 + components = [encodeFun(x, **options) for x in value] + + # sort by serialized and padded components + if len(components) > 1: + zero = str2octs('\x00') + maxLen = max(map(len, components)) + paddedComponents = [ + (x.ljust(maxLen, zero), x) for x in components + ] + paddedComponents.sort(key=lambda x: x[0]) + + components = [x[1] for x in paddedComponents] + + substrate = null.join(components) + + return substrate, True, True + + +class SequenceEncoder(encoder.SequenceEncoder): + def encodeValue(self, value, encodeFun, **options): + value.verifySizeSpec() + + namedTypes = value.componentType + substrate = null + + idx = len(value) + while idx > 0: + idx -= 1 + if namedTypes: + if namedTypes[idx].isOptional and not value[idx].isValue: + continue + if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object: + continue + + options.update(ifNotEmpty=namedTypes and namedTypes[idx].isOptional) + + substrate = encodeFun(value[idx], **options) + substrate + + return substrate, True, True + + +class SequenceOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, encodeFun, **options): + substrate = null + idx = len(value) + + if options.get('ifNotEmpty', False) and not idx: + return substrate, True, True + + value.verifySizeSpec() + while idx > 0: + idx -= 1 + substrate = encodeFun(value[idx], **options) + substrate + return substrate, True, True + tagMap = encoder.tagMap.copy() tagMap.update({ univ.Boolean.tagSet: BooleanEncoder(), - univ.BitString.tagSet: BitStringEncoder(), - univ.OctetString.tagSet: OctetStringEncoder(), - univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set - }) + univ.Real.tagSet: RealEncoder(), + useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(), + useful.UTCTime.tagSet: UTCTimeEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SetOf.tagSet: SetOfEncoder(), + univ.Sequence.typeId: SequenceEncoder() +}) typeMap = encoder.typeMap.copy() typeMap.update({ + univ.Boolean.typeId: BooleanEncoder(), + univ.Real.typeId: RealEncoder(), + useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(), + useful.UTCTime.typeId: UTCTimeEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf univ.Set.typeId: SetOfEncoder(), - univ.SetOf.typeId: SetOfEncoder() - }) + univ.SetOf.typeId: SetOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder() +}) + class Encoder(encoder.Encoder): - def __call__(self, client, defMode=0, maxChunkSize=0): - return encoder.Encoder.__call__(self, client, defMode, maxChunkSize) + fixedDefLengthMode = False + fixedChunkSize = 1000 +#: Turns ASN.1 object into CER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a CER octet stream. +#: +#: Parameters +#: ---------- +# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A pyasn1 object to encode +#: +#: 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) +#: Given ASN.1 object encoded into BER octetstream +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On encoding errors encode = Encoder(tagMap, typeMap) # EncoderFactory queries class instance and builds a map of tags -> encoders diff --git a/third_party/python/pyasn1/pyasn1/codec/der/decoder.py b/third_party/python/pyasn1/pyasn1/codec/der/decoder.py index 604abec2bc2b..77b1cec5388b 100644 --- a/third_party/python/pyasn1/pyasn1/codec/der/decoder.py +++ b/third_party/python/pyasn1/pyasn1/codec/der/decoder.py @@ -1,9 +1,70 @@ -# DER decoder +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1.type import univ from pyasn1.codec.cer import decoder -tagMap = decoder.tagMap -typeMap = decoder.typeMap -Decoder = decoder.Decoder +__all__ = ['decode'] + +class BitStringDecoder(decoder.BitStringDecoder): + supportConstructedForm = False + + +class OctetStringDecoder(decoder.OctetStringDecoder): + supportConstructedForm = False + +# TODO: prohibit non-canonical encoding +RealDecoder = decoder.RealDecoder + +tagMap = decoder.tagMap.copy() +tagMap.update( + {univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: OctetStringDecoder(), + univ.Real.tagSet: RealDecoder()} +) + +typeMap = decoder.typeMap.copy() + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in tagMap.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in typeMap: + typeMap[typeId] = typeDecoder + + +class Decoder(decoder.Decoder): + supportIndefLength = False + + +#: Turns DER octet stream into an ASN.1 object. +#: +#: Takes DER octetstream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: DER octetstream +#: +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from DER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On decoding errors decode = Decoder(tagMap, typeMap) diff --git a/third_party/python/pyasn1/pyasn1/codec/der/encoder.py b/third_party/python/pyasn1/pyasn1/codec/der/encoder.py index 4e5faefad4d0..d2992a96b668 100644 --- a/third_party/python/pyasn1/pyasn1/codec/der/encoder.py +++ b/third_party/python/pyasn1/pyasn1/codec/der/encoder.py @@ -1,28 +1,62 @@ -# DER encoder +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1.type import univ from pyasn1.codec.cer import encoder +__all__ = ['encode'] + + class SetOfEncoder(encoder.SetOfEncoder): - def _cmpSetComponents(self, c1, c2): - tagSet1 = isinstance(c1, univ.Choice) and \ - c1.getEffectiveTagSet() or c1.getTagSet() - tagSet2 = isinstance(c2, univ.Choice) and \ - c2.getEffectiveTagSet() or c2.getTagSet() - return cmp(tagSet1, tagSet2) + @staticmethod + def _sortComponents(components): + # sort by tags depending on the actual Choice value (dynamic sort) + return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.getComponent().tagSet or x.tagSet) tagMap = encoder.tagMap.copy() tagMap.update({ - # Overload CER encodrs with BER ones (a bit hackerish XXX) - univ.BitString.tagSet: encoder.encoder.BitStringEncoder(), - univ.OctetString.tagSet: encoder.encoder.OctetStringEncoder(), # Set & SetOf have same tags - univ.SetOf().tagSet: SetOfEncoder() - }) + univ.SetOf.tagSet: SetOfEncoder() +}) + +typeMap = encoder.typeMap.copy() +typeMap.update({ + # Set & SetOf have same tags + univ.Set.typeId: SetOfEncoder(), + univ.SetOf.typeId: SetOfEncoder() +}) -typeMap = encoder.typeMap class Encoder(encoder.Encoder): - def __call__(self, client, defMode=1, maxChunkSize=0): - return encoder.Encoder.__call__(self, client, defMode, maxChunkSize) - + fixedDefLengthMode = True + fixedChunkSize = 0 + +#: Turns ASN.1 object into DER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a DER octet stream. +#: +#: Parameters +#: ---------- +# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A pyasn1 object to encode +#: +#: 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) +#: Given ASN.1 object encoded into BER octetstream +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On encoding errors encode = Encoder(tagMap, typeMap) diff --git a/third_party/python/pyasn1/test/__init__.py b/third_party/python/pyasn1/pyasn1/codec/native/__init__.py similarity index 100% rename from third_party/python/pyasn1/test/__init__.py rename to third_party/python/pyasn1/pyasn1/codec/native/__init__.py diff --git a/third_party/python/pyasn1/pyasn1/codec/native/decoder.py b/third_party/python/pyasn1/pyasn1/codec/native/decoder.py new file mode 100644 index 000000000000..70b22a85fe2b --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/codec/native/decoder.py @@ -0,0 +1,194 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from pyasn1.type import base, univ, char, useful, tag +from pyasn1 import debug, error + +__all__ = ['decode'] + + +class AbstractScalarDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + return asn1Spec.clone(pyObject) + + +class BitStringDecoder(AbstractScalarDecoder): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + return asn1Spec.clone(univ.BitString.fromBinaryString(pyObject)) + + +class SequenceOrSetDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + componentsTypes = asn1Spec.componentType + + for field in asn1Value: + if field in pyObject: + asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options) + + return asn1Value + + +class SequenceOfOrSetOfDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + for pyValue in pyObject: + asn1Value.append(decodeFun(pyValue, asn1Spec.componentType), **options) + + return asn1Value + + +class ChoiceDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + componentsTypes = asn1Spec.componentType + + for field in pyObject: + if field in componentsTypes: + asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options) + break + + return asn1Value + + +tagMap = { + univ.Integer.tagSet: AbstractScalarDecoder(), + univ.Boolean.tagSet: AbstractScalarDecoder(), + univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: AbstractScalarDecoder(), + univ.Null.tagSet: AbstractScalarDecoder(), + univ.ObjectIdentifier.tagSet: AbstractScalarDecoder(), + univ.Enumerated.tagSet: AbstractScalarDecoder(), + univ.Real.tagSet: AbstractScalarDecoder(), + univ.Sequence.tagSet: SequenceOrSetDecoder(), # conflicts with SequenceOf + univ.Set.tagSet: SequenceOrSetDecoder(), # conflicts with SetOf + univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any + # character string types + char.UTF8String.tagSet: AbstractScalarDecoder(), + char.NumericString.tagSet: AbstractScalarDecoder(), + char.PrintableString.tagSet: AbstractScalarDecoder(), + char.TeletexString.tagSet: AbstractScalarDecoder(), + char.VideotexString.tagSet: AbstractScalarDecoder(), + char.IA5String.tagSet: AbstractScalarDecoder(), + char.GraphicString.tagSet: AbstractScalarDecoder(), + char.VisibleString.tagSet: AbstractScalarDecoder(), + char.GeneralString.tagSet: AbstractScalarDecoder(), + char.UniversalString.tagSet: AbstractScalarDecoder(), + char.BMPString.tagSet: AbstractScalarDecoder(), + # useful types + useful.ObjectDescriptor.tagSet: AbstractScalarDecoder(), + useful.GeneralizedTime.tagSet: AbstractScalarDecoder(), + useful.UTCTime.tagSet: AbstractScalarDecoder() +} + +# Put in ambiguous & non-ambiguous types for faster codec lookup +typeMap = { + univ.Integer.typeId: AbstractScalarDecoder(), + univ.Boolean.typeId: AbstractScalarDecoder(), + univ.BitString.typeId: BitStringDecoder(), + univ.OctetString.typeId: AbstractScalarDecoder(), + univ.Null.typeId: AbstractScalarDecoder(), + univ.ObjectIdentifier.typeId: AbstractScalarDecoder(), + univ.Enumerated.typeId: AbstractScalarDecoder(), + univ.Real.typeId: AbstractScalarDecoder(), + # ambiguous base types + univ.Set.typeId: SequenceOrSetDecoder(), + univ.SetOf.typeId: SequenceOfOrSetOfDecoder(), + univ.Sequence.typeId: SequenceOrSetDecoder(), + univ.SequenceOf.typeId: SequenceOfOrSetOfDecoder(), + univ.Choice.typeId: ChoiceDecoder(), + univ.Any.typeId: AbstractScalarDecoder(), + # character string types + char.UTF8String.typeId: AbstractScalarDecoder(), + char.NumericString.typeId: AbstractScalarDecoder(), + char.PrintableString.typeId: AbstractScalarDecoder(), + char.TeletexString.typeId: AbstractScalarDecoder(), + char.VideotexString.typeId: AbstractScalarDecoder(), + char.IA5String.typeId: AbstractScalarDecoder(), + char.GraphicString.typeId: AbstractScalarDecoder(), + char.VisibleString.typeId: AbstractScalarDecoder(), + char.GeneralString.typeId: AbstractScalarDecoder(), + char.UniversalString.typeId: AbstractScalarDecoder(), + char.BMPString.typeId: AbstractScalarDecoder(), + # useful types + useful.ObjectDescriptor.typeId: AbstractScalarDecoder(), + useful.GeneralizedTime.typeId: AbstractScalarDecoder(), + useful.UTCTime.typeId: AbstractScalarDecoder() +} + + +class Decoder(object): + + # noinspection PyDefaultArgument + def __init__(self, tagMap, typeMap): + self.__tagMap = tagMap + self.__typeMap = typeMap + + def __call__(self, pyObject, asn1Spec, **options): + if debug.logger & debug.flagDecoder: + logger = debug.logger + else: + logger = None + if logger: + debug.scope.push(type(pyObject).__name__) + logger('decoder called at scope %s, working with type %s' % (debug.scope, type(pyObject).__name__)) + + if asn1Spec is None or not isinstance(asn1Spec, base.Asn1Item): + raise error.PyAsn1Error('asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__) + + try: + valueDecoder = self.__typeMap[asn1Spec.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(asn1Spec.tagSet.baseTag, asn1Spec.tagSet.baseTag) + + try: + valueDecoder = self.__tagMap[baseTagSet] + except KeyError: + raise error.PyAsn1Error('Unknown ASN.1 tag %s' % asn1Spec.tagSet) + + if logger: + logger('calling decoder %s on Python type %s <%s>' % (type(valueDecoder).__name__, type(pyObject).__name__, repr(pyObject))) + + value = valueDecoder(pyObject, asn1Spec, self, **options) + + if logger: + logger('decoder %s produced ASN.1 type %s <%s>' % (type(valueDecoder).__name__, type(value).__name__, repr(value))) + debug.scope.pop() + + return value + + +#: Turns Python objects of built-in types into ASN.1 objects. +#: +#: Takes Python objects of built-in types and turns them into a tree of +#: ASN.1 objects (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: pyObject: :py:class:`object` +#: A scalar or nested Python objects +#: +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. It is required +#: for successful interpretation of Python objects mapping into their ASN.1 +#: representations. +#: +#: Returns +#: ------- +#: : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A scalar or constructed pyasn1 object +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On decoding errors +decode = Decoder(tagMap, typeMap) diff --git a/third_party/python/pyasn1/pyasn1/codec/native/encoder.py b/third_party/python/pyasn1/pyasn1/codec/native/encoder.py new file mode 100644 index 000000000000..3d23d60631d1 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/codec/native/encoder.py @@ -0,0 +1,212 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + from collections import OrderedDict + +except ImportError: + OrderedDict = dict + +from pyasn1.type import base, univ, tag, char, useful +from pyasn1 import debug, error + +__all__ = ['encode'] + + +class AbstractItemEncoder(object): + def encode(self, value, encodeFun, **options): + raise error.PyAsn1Error('Not implemented') + + +class BooleanEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return bool(value) + + +class IntegerEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return int(value) + + +class BitStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class OctetStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.asOctets() + + +class TextStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.prettyPrint() + + +class NullEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return None + + +class ObjectIdentifierEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class RealEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return float(value) + + +class SetEncoder(AbstractItemEncoder): + protoDict = dict + + def encode(self, value, encodeFun, **options): + value.verifySizeSpec() + + namedTypes = value.componentType + substrate = self.protoDict() + + for idx, (key, subValue) in enumerate(value.items()): + if namedTypes and namedTypes[idx].isOptional and not value[idx].isValue: + continue + substrate[key] = encodeFun(subValue, **options) + return substrate + + +class SequenceEncoder(SetEncoder): + protoDict = OrderedDict + + +class SequenceOfEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + value.verifySizeSpec() + return [encodeFun(x, **options) for x in value] + + +class ChoiceEncoder(SequenceEncoder): + pass + + +class AnyEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.asOctets() + + +tagMap = { + univ.Boolean.tagSet: BooleanEncoder(), + univ.Integer.tagSet: IntegerEncoder(), + univ.BitString.tagSet: BitStringEncoder(), + univ.OctetString.tagSet: OctetStringEncoder(), + univ.Null.tagSet: NullEncoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), + univ.Enumerated.tagSet: IntegerEncoder(), + univ.Real.tagSet: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SequenceOf.tagSet: SequenceOfEncoder(), + univ.SetOf.tagSet: SequenceOfEncoder(), + univ.Choice.tagSet: ChoiceEncoder(), + # character string types + char.UTF8String.tagSet: TextStringEncoder(), + char.NumericString.tagSet: TextStringEncoder(), + char.PrintableString.tagSet: TextStringEncoder(), + char.TeletexString.tagSet: TextStringEncoder(), + char.VideotexString.tagSet: TextStringEncoder(), + char.IA5String.tagSet: TextStringEncoder(), + char.GraphicString.tagSet: TextStringEncoder(), + char.VisibleString.tagSet: TextStringEncoder(), + char.GeneralString.tagSet: TextStringEncoder(), + char.UniversalString.tagSet: TextStringEncoder(), + char.BMPString.tagSet: TextStringEncoder(), + # useful types + useful.ObjectDescriptor.tagSet: OctetStringEncoder(), + useful.GeneralizedTime.tagSet: OctetStringEncoder(), + useful.UTCTime.tagSet: OctetStringEncoder() +} + +# Type-to-codec map for ambiguous ASN.1 types +typeMap = { + univ.Set.typeId: SetEncoder(), + univ.SetOf.typeId: SequenceOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder(), + univ.Choice.typeId: ChoiceEncoder(), + univ.Any.typeId: AnyEncoder() +} + + +class Encoder(object): + + # noinspection PyDefaultArgument + def __init__(self, tagMap, typeMap={}): + self.__tagMap = tagMap + self.__typeMap = typeMap + + def __call__(self, value, **options): + if not isinstance(value, base.Asn1Item): + raise error.PyAsn1Error('value is not valid (should be an instance of an ASN.1 Item)') + + if debug.logger & debug.flagEncoder: + logger = debug.logger + else: + logger = None + + if logger: + debug.scope.push(type(value).__name__) + logger('encoder called for type %s <%s>' % (type(value).__name__, value.prettyPrint())) + + tagSet = value.tagSet + + try: + concreteEncoder = self.__typeMap[value.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) + + try: + concreteEncoder = self.__tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('No encoder for %s' % (value,)) + + if logger: + logger('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) + + pyObject = concreteEncoder.encode(value, self, **options) + + if logger: + logger('encoder %s produced: %s' % (type(concreteEncoder).__name__, repr(pyObject))) + debug.scope.pop() + + return pyObject + + +#: Turns ASN.1 object into a Python built-in type object(s). +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a Python built-in type or a tree +#: of those. +#: +#: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict` +#: can be produced (whenever available) to preserve ordering of the components +#: in ASN.1 SEQUENCE. +#: +#: Parameters +#: ---------- +# asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: pyasn1 object to encode (or a tree of them) +#: +#: Returns +#: ------- +#: : :py:class:`object` +#: Python built-in type instance (or a tree of them) +#: +#: Raises +#: ------ +#: : :py:class:`pyasn1.error.PyAsn1Error` +#: On encoding errors +encode = Encoder(tagMap, typeMap) diff --git a/third_party/python/pyasn1/pyasn1/compat/binary.py b/third_party/python/pyasn1/pyasn1/compat/binary.py new file mode 100644 index 000000000000..86f6e5d0b272 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/compat/binary.py @@ -0,0 +1,33 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from sys import version_info + +if version_info[0:2] < (2, 6): + def bin(value): + bitstring = [] + + if value > 0: + prefix = '0b' + elif value < 0: + prefix = '-0b' + value = abs(value) + else: + prefix = '0b0' + + while value: + if value & 1 == 1: + bitstring.append('1') + else: + bitstring.append('0') + + value >>= 1 + + bitstring.reverse() + + return prefix + ''.join(bitstring) +else: + bin = bin diff --git a/third_party/python/pyasn1/pyasn1/compat/calling.py b/third_party/python/pyasn1/pyasn1/compat/calling.py new file mode 100644 index 000000000000..fde25d8013d5 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/compat/calling.py @@ -0,0 +1,20 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from sys import version_info + +__all__ = ['callable'] + + +if (2, 7) < version_info[:2] < (3, 2): + import collections + + def callable(x): + return isinstance(x, collections.Callable) + +else: + + callable = callable diff --git a/third_party/python/pyasn1/pyasn1/compat/dateandtime.py b/third_party/python/pyasn1/pyasn1/compat/dateandtime.py new file mode 100644 index 000000000000..646b9e8596b7 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/compat/dateandtime.py @@ -0,0 +1,22 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from sys import version_info +from datetime import datetime +import time + +__all__ = ['strptime'] + + +if version_info[:2] <= (2, 4): + + def strptime(text, dateFormat): + return datetime(*(time.strptime(text, dateFormat)[0:6])) + +else: + + def strptime(text, dateFormat): + return datetime.strptime(text, dateFormat) diff --git a/third_party/python/pyasn1/pyasn1/compat/integer.py b/third_party/python/pyasn1/pyasn1/compat/integer.py new file mode 100644 index 000000000000..0c426a2e86d7 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/compat/integer.py @@ -0,0 +1,108 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys +try: + import platform + implementation = platform.python_implementation() + +except (ImportError, AttributeError): + implementation = 'CPython' + +from pyasn1.compat.octets import oct2int, null, ensureString + +if sys.version_info[0:2] < (3, 2) or implementation != 'CPython': + from binascii import a2b_hex, b2a_hex + + if sys.version_info[0] > 2: + long = int + + def from_bytes(octets, signed=False): + if not octets: + return 0 + + value = long(b2a_hex(ensureString(octets)), 16) + + if signed and oct2int(octets[0]) & 0x80: + return value - (1 << len(octets) * 8) + + return value + + def to_bytes(value, signed=False, length=0): + if value < 0: + if signed: + bits = bitLength(value) + + # two's complement form + maxValue = 1 << bits + valueToEncode = (value + maxValue) % maxValue + + else: + raise OverflowError('can\'t convert negative int to unsigned') + elif value == 0 and length == 0: + return null + else: + bits = 0 + valueToEncode = value + + hexValue = hex(valueToEncode)[2:] + if hexValue.endswith('L'): + hexValue = hexValue[:-1] + + if len(hexValue) & 1: + hexValue = '0' + hexValue + + # padding may be needed for two's complement encoding + if value != valueToEncode or length: + hexLength = len(hexValue) * 4 + + padLength = max(length, bits) + + if padLength > hexLength: + hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue + elif length and hexLength - length > 7: + raise OverflowError('int too big to convert') + + firstOctet = int(hexValue[:2], 16) + + if signed: + if firstOctet & 0x80: + if value >= 0: + hexValue = '00' + hexValue + elif value < 0: + hexValue = 'ff' + hexValue + + octets_value = a2b_hex(hexValue) + + return octets_value + + def bitLength(number): + # bits in unsigned number + hexValue = hex(abs(number)) + bits = len(hexValue) - 2 + if hexValue.endswith('L'): + bits -= 1 + if bits & 1: + bits += 1 + bits *= 4 + # TODO: strip lhs zeros + return bits + +else: + + def from_bytes(octets, signed=False): + return int.from_bytes(bytes(octets), 'big', signed=signed) + + def to_bytes(value, signed=False, length=0): + length = max(value.bit_length(), length) + + if signed and length % 8 == 0: + length += 1 + + return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed) + + def bitLength(number): + return int(number).bit_length() diff --git a/third_party/python/pyasn1/pyasn1/compat/octets.py b/third_party/python/pyasn1/pyasn1/compat/octets.py index f7f2a29bf561..f8d47089671b 100644 --- a/third_party/python/pyasn1/pyasn1/compat/octets.py +++ b/third_party/python/pyasn1/pyasn1/compat/octets.py @@ -1,20 +1,46 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from sys import version_info if version_info[0] <= 2: int2oct = chr - ints2octs = lambda s: ''.join([ int2oct(x) for x in s ]) + # noinspection PyPep8 + ints2octs = lambda s: ''.join([int2oct(x) for x in s]) null = '' oct2int = ord - octs2ints = lambda s: [ oct2int(x) for x in s ] + # TODO: refactor to return a sequence of ints + # noinspection PyPep8 + octs2ints = lambda s: [oct2int(x) for x in s] + # noinspection PyPep8 str2octs = lambda x: x + # noinspection PyPep8 octs2str = lambda x: x + # noinspection PyPep8 isOctetsType = lambda s: isinstance(s, str) + # noinspection PyPep8 + isStringType = lambda s: isinstance(s, (str, unicode)) + # noinspection PyPep8 + ensureString = str else: ints2octs = bytes + # noinspection PyPep8 int2oct = lambda x: ints2octs((x,)) null = ints2octs() + # noinspection PyPep8 oct2int = lambda x: x - octs2ints = lambda s: [ x for x in s ] - str2octs = lambda x: x.encode() - octs2str = lambda x: x.decode() + # noinspection PyPep8 + octs2ints = lambda x: x + # noinspection PyPep8 + str2octs = lambda x: x.encode('iso-8859-1') + # noinspection PyPep8 + octs2str = lambda x: x.decode('iso-8859-1') + # noinspection PyPep8 isOctetsType = lambda s: isinstance(s, bytes) + # noinspection PyPep8 + isStringType = lambda s: isinstance(s, str) + # noinspection PyPep8 + ensureString = bytes diff --git a/third_party/python/pyasn1/pyasn1/compat/string.py b/third_party/python/pyasn1/pyasn1/compat/string.py new file mode 100644 index 000000000000..24e64b680061 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1/compat/string.py @@ -0,0 +1,26 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +from sys import version_info + +if version_info[:2] <= (2, 5): + + def partition(string, sep): + try: + a, c = string.split(sep, 1) + + except ValueError: + a, b, c = string, '', '' + + else: + b = sep + + return a, b, c + +else: + + def partition(string, sep): + return string.partition(sep) diff --git a/third_party/python/pyasn1/pyasn1/debug.py b/third_party/python/pyasn1/pyasn1/debug.py index c27cb1d44650..24ac5ce07256 100644 --- a/third_party/python/pyasn1/pyasn1/debug.py +++ b/third_party/python/pyasn1/pyasn1/debug.py @@ -1,36 +1,105 @@ -import sys +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import logging from pyasn1.compat.octets import octs2ints from pyasn1 import error from pyasn1 import __version__ -flagNone = 0x0000 -flagEncoder = 0x0001 -flagDecoder = 0x0002 -flagAll = 0xffff +__all__ = ['Debug', 'setLogger', 'hexdump'] + +flagNone = 0x0000 +flagEncoder = 0x0001 +flagDecoder = 0x0002 +flagAll = 0xffff flagMap = { 'encoder': flagEncoder, 'decoder': flagDecoder, 'all': flagAll - } +} -class Debug: - defaultPrinter = sys.stderr.write - def __init__(self, *flags): + +class Printer(object): + # noinspection PyShadowingNames + def __init__(self, logger=None, handler=None, formatter=None): + if logger is None: + logger = logging.getLogger('pyasn1') + + logger.setLevel(logging.DEBUG) + + if handler is None: + handler = logging.StreamHandler() + + if formatter is None: + formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') + + handler.setFormatter(formatter) + handler.setLevel(logging.DEBUG) + logger.addHandler(handler) + + self.__logger = logger + + def __call__(self, msg): + self.__logger.debug(msg) + + def __str__(self): + return '' + + +if hasattr(logging, 'NullHandler'): + NullHandler = logging.NullHandler + +else: + # Python 2.6 and older + class NullHandler(logging.Handler): + def emit(self, record): + pass + + +class Debug(object): + defaultPrinter = Printer() + + def __init__(self, *flags, **options): self._flags = flagNone - self._printer = self.defaultPrinter - self('running pyasn1 version %s' % __version__) - for f in flags: - if f not in flagMap: - raise error.PyAsn1Error('bad debug flag %s' % (f,)) - self._flags = self._flags | flagMap[f] - self('debug category \'%s\' enabled' % f) - + + if 'loggerName' in options: + # route our logs to parent logger + self._printer = Printer( + logger=logging.getLogger(options['loggerName']), + handler=NullHandler() + ) + + elif 'printer' in options: + self._printer = options.get('printer') + + else: + self._printer = self.defaultPrinter + + self._printer('running pyasn1 %s, debug flags %s' % (__version__, ', '.join(flags))) + + for flag in flags: + inverse = flag and flag[0] in ('!', '~') + if inverse: + flag = flag[1:] + try: + if inverse: + self._flags &= ~flagMap[flag] + else: + self._flags |= flagMap[flag] + except KeyError: + raise error.PyAsn1Error('bad debug flag %s' % flag) + + self._printer("debug category '%s' %s" % (flag, inverse and 'disabled' or 'enabled')) + def __str__(self): return 'logger %s, flags %x' % (self._printer, self._flags) - + def __call__(self, msg): - self._printer('DBG: %s\n' % msg) + self._printer(msg) def __and__(self, flag): return self._flags & flag @@ -38,19 +107,27 @@ class Debug: def __rand__(self, flag): return flag & self._flags + logger = 0 -def setLogger(l): + +def setLogger(userLogger): global logger - logger = l + + if userLogger: + logger = userLogger + else: + logger = 0 + def hexdump(octets): return ' '.join( - [ '%s%.2X' % (n%16 == 0 and ('\n%.5d: ' % n) or '', x) - for n,x in zip(range(len(octets)), octs2ints(octets)) ] - ) + ['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) + for n, x in zip(range(len(octets)), octs2ints(octets))] + ) -class Scope: + +class Scope(object): def __init__(self): self._list = [] @@ -62,4 +139,5 @@ class Scope: def pop(self): return self._list.pop() + scope = Scope() diff --git a/third_party/python/pyasn1/pyasn1/error.py b/third_party/python/pyasn1/pyasn1/error.py index 716406ff63a1..85308557b352 100644 --- a/third_party/python/pyasn1/pyasn1/error.py +++ b/third_party/python/pyasn1/pyasn1/error.py @@ -1,3 +1,18 @@ -class PyAsn1Error(Exception): pass -class ValueConstraintError(PyAsn1Error): pass -class SubstrateUnderrunError(PyAsn1Error): pass +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# + + +class PyAsn1Error(Exception): + pass + + +class ValueConstraintError(PyAsn1Error): + pass + + +class SubstrateUnderrunError(PyAsn1Error): + pass diff --git a/third_party/python/pyasn1/pyasn1/type/base.py b/third_party/python/pyasn1/pyasn1/type/base.py index 40873719caa9..1b54d8d24a9c 100644 --- a/third_party/python/pyasn1/pyasn1/type/base.py +++ b/third_party/python/pyasn1/pyasn1/type/base.py @@ -1,134 +1,394 @@ -# Base classes for ASN.1 types +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# import sys -from pyasn1.type import constraint, tagmap +from pyasn1.type import constraint, tagmap, tag +from pyasn1.compat import calling from pyasn1 import error -class Asn1Item: pass +__all__ = ['Asn1Item', 'Asn1ItemBase', 'AbstractSimpleAsn1Item', 'AbstractConstructedAsn1Item'] + + +class Asn1Item(object): + @classmethod + def getTypeId(cls, increment=1): + try: + Asn1Item._typeCounter += increment + except AttributeError: + Asn1Item._typeCounter = increment + return Asn1Item._typeCounter + class Asn1ItemBase(Asn1Item): - # Set of tags for this ASN.1 type - tagSet = () - - # A list of constraint.Constraint instances for checking values + #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing + #: ASN.1 tag(s) associated with |ASN.1| type. + tagSet = tag.TagSet() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing constraints on initialization values. subtypeSpec = constraint.ConstraintsIntersection() - # Used for ambiguous ASN.1 types identification + # Disambiguation ASN.1 types identification typeId = None - - def __init__(self, tagSet=None, subtypeSpec=None): - if tagSet is None: - self._tagSet = self.tagSet - else: - self._tagSet = tagSet - if subtypeSpec is None: - self._subtypeSpec = self.subtypeSpec - else: - self._subtypeSpec = subtypeSpec - def _verifySubtypeSpec(self, value, idx=None): - try: - self._subtypeSpec(value, idx) - except error.PyAsn1Error: - c, i, t = sys.exc_info() - raise c('%s at %s' % (i, self.__class__.__name__)) + def __init__(self, **kwargs): + readOnly = { + 'tagSet': self.tagSet, + 'subtypeSpec': self.subtypeSpec + } + + readOnly.update(kwargs) + + self.__dict__.update(readOnly) + + self._readOnly = readOnly + + def __setattr__(self, name, value): + if name[0] != '_' and name in self._readOnly: + raise error.PyAsn1Error('read-only instance attribute "%s"' % name) + + self.__dict__[name] = value + + @property + def readOnly(self): + return self._readOnly + + @property + def effectiveTagSet(self): + """For |ASN.1| type is equivalent to *tagSet* + """ + return self.tagSet # used by untagged types + + @property + def tagMap(self): + """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object. + """ + return tagmap.TagMap({self.tagSet: self}) + + def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): + """Examine |ASN.1| type for equality with other ASN.1 type. + + ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints + (:py:mod:`~pyasn1.type.constraint`) are examined when carrying + out ASN.1 types comparison. + + No Python inheritance relationship between PyASN1 objects is considered. + + Parameters + ---------- + other: a pyasn1 type object + Class instance representing ASN.1 type. + + Returns + ------- + : :class:`bool` + :class:`True` if *other* is |ASN.1| type, + :class:`False` otherwise. + """ + return (self is other or + (not matchTags or self.tagSet == other.tagSet) and + (not matchConstraints or self.subtypeSpec == other.subtypeSpec)) + + def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): + """Examine |ASN.1| type for subtype relationship with other ASN.1 type. - def getSubtypeSpec(self): return self._subtypeSpec - - def getTagSet(self): return self._tagSet - def getEffectiveTagSet(self): return self._tagSet # used by untagged types - def getTagMap(self): return tagmap.TagMap({self._tagSet: self}) - - def isSameTypeWith(self, other): - return self is other or \ - self._tagSet == other.getTagSet() and \ - self._subtypeSpec == other.getSubtypeSpec() - def isSuperTypeOf(self, other): - """Returns true if argument is a ASN1 subtype of ourselves""" - return self._tagSet.isSuperTagSetOf(other.getTagSet()) and \ - self._subtypeSpec.isSuperTypeOf(other.getSubtypeSpec()) + ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints + (:py:mod:`~pyasn1.type.constraint`) are examined when carrying + out ASN.1 types comparison. + + No Python inheritance relationship between PyASN1 objects is considered. + + + Parameters + ---------- + other: a pyasn1 type object + Class instance representing ASN.1 type. + + Returns + ------- + : :class:`bool` + :class:`True` if *other* is a subtype of |ASN.1| type, + :class:`False` otherwise. + """ + return (not matchTags or + (self.tagSet.isSuperTagSetOf(other.tagSet)) and + (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec))) + + @staticmethod + def isNoValue(*values): + for value in values: + if value is not None and value is not noValue: + return False + return True + + # backward compatibility + + def getTagSet(self): + return self.tagSet + + def getEffectiveTagSet(self): + return self.effectiveTagSet + + def getTagMap(self): + return self.tagMap + + def getSubtypeSpec(self): + return self.subtypeSpec + + def hasValue(self): + return self.isValue + + +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. + + No operations other than type comparison can be performed on + a PyASN1 type object. + """ + skipMethods = ('__getattribute__', '__getattr__', '__setattr__', '__delattr__', + '__class__', '__init__', '__del__', '__new__', '__repr__', + '__qualname__', '__objclass__', 'im_class', '__sizeof__') + + _instance = None + + def __new__(cls): + 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) + return plug + + op_names = [name + for typ in (str, int, list, dict) + for name in dir(typ) + if (name not in cls.skipMethods and + name.startswith('__') and + name.endswith('__') and + calling.callable(getattr(typ, name)))] + + for name in set(op_names): + setattr(cls, name, getPlug(name)) + + cls._instance = object.__new__(cls) + + return cls._instance -class __NoValue: def __getattr__(self, attr): - raise error.PyAsn1Error('No value for %s()' % attr) - def __getitem__(self, i): - raise error.PyAsn1Error('No value') - -noValue = __NoValue() + if attr in self.skipMethods: + raise AttributeError('attribute %s not present' % attr) + raise error.PyAsn1Error('No value for "%s"' % attr) + + def __repr__(self): + return '%s()' % self.__class__.__name__ + +noValue = NoValue() + # Base class for "simple" ASN.1 objects. These are immutable. -class AbstractSimpleAsn1Item(Asn1ItemBase): +class AbstractSimpleAsn1Item(Asn1ItemBase): + #: Default payload value defaultValue = noValue - def __init__(self, value=None, tagSet=None, subtypeSpec=None): - Asn1ItemBase.__init__(self, tagSet, subtypeSpec) - if value is None or value is noValue: + + def __init__(self, value=noValue, **kwargs): + Asn1ItemBase.__init__(self, **kwargs) + if value is noValue or value is None: value = self.defaultValue - if value is None or value is noValue: - self.__hashedValue = value = noValue else: value = self.prettyIn(value) - self._verifySubtypeSpec(value) - self.__hashedValue = hash(value) + try: + self.subtypeSpec(value) + + except error.PyAsn1Error: + exType, exValue, exTb = sys.exc_info() + raise exType('%s at %s' % (exValue, self.__class__.__name__)) + self._value = value - self._len = None - + def __repr__(self): - if self._value is noValue: - return self.__class__.__name__ + '()' - else: - return self.__class__.__name__ + '(%s)' % (self.prettyOut(self._value),) - def __str__(self): return str(self._value) + representation = [] + if self._value is not self.defaultValue: + representation.append(self.prettyOut(self._value)) + if self.tagSet is not self.__class__.tagSet: + representation.append('tagSet=%r' % (self.tagSet,)) + if self.subtypeSpec is not self.__class__.subtypeSpec: + representation.append('subtypeSpec=%r' % (self.subtypeSpec,)) + return '%s(%s)' % (self.__class__.__name__, ', '.join(representation)) + + def __str__(self): + return str(self._value) + def __eq__(self, other): return self is other and True or self._value == other - def __ne__(self, other): return self._value != other - def __lt__(self, other): return self._value < other - def __le__(self, other): return self._value <= other - def __gt__(self, other): return self._value > other - def __ge__(self, other): return self._value >= other + + def __ne__(self, other): + return self._value != other + + def __lt__(self, other): + return self._value < other + + def __le__(self, other): + return self._value <= other + + def __gt__(self, other): + return self._value > other + + def __ge__(self, other): + return self._value >= other + if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._value) + def __nonzero__(self): + return self._value and True or False else: - def __bool__(self): return bool(self._value) - def __hash__(self): return self.__hashedValue + def __bool__(self): + return self._value and True or False - def clone(self, value=None, tagSet=None, subtypeSpec=None): - if value is None and tagSet is None and subtypeSpec is None: - return self - if value is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - return self.__class__(value, tagSet, subtypeSpec) + def __hash__(self): + return hash(self._value) + + @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. + + Returns + ------- + : :class:`bool` + :class:`True` if object represents ASN.1 value and type, + :class:`False` if object represents just ASN.1 type. + + 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. + """ + return self._value is not noValue + + def clone(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`tuple`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + if value is noValue or value is None: + if not kwargs: + return self - def subtype(self, value=None, implicitTag=None, explicitTag=None, - subtypeSpec=None): - if value is None: value = self._value + + initilaizers = self.readOnly.copy() + initilaizers.update(kwargs) + + return self.__class__(value, **initilaizers) + + def subtype(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`tuple`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the caller, then + use the result as new object's ASN.1 constraints. + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + if value is noValue or value is None: + if not kwargs: + return self + + value = self._value + + initializers = self.readOnly.copy() + + implicitTag = kwargs.pop('implicitTag', None) if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - return self.__class__(value, tagSet, subtypeSpec) + initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) - def prettyIn(self, value): return value - def prettyOut(self, value): return str(value) + explicitTag = kwargs.pop('explicitTag', None) + if explicitTag is not None: + initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) + + for arg, option in kwargs.items(): + initializers[arg] += option + + return self.__class__(value, **initializers) + + def prettyIn(self, value): + return value + + def prettyOut(self, value): + return str(value) def prettyPrint(self, scope=0): - if self._value is noValue: - return '' - else: + """Provide human-friendly printable object representation. + + Returns + ------- + : :class:`str` + human-friendly type and/or value representation. + """ + if self.isValue: return self.prettyOut(self._value) + else: + return '' # XXX Compatibility stub - def prettyPrinter(self, scope=0): return self.prettyPrint(scope) - + def prettyPrinter(self, scope=0): + return self.prettyPrint(scope) + + # noinspection PyUnusedLocal + def prettyPrintType(self, scope=0): + return '%s -> %s' % (self.tagSet, self.__class__.__name__) + # # Constructed types: # * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice @@ -148,102 +408,194 @@ class AbstractSimpleAsn1Item(Asn1ItemBase): # of types for Sequence/Set/Choice. # +def setupComponent(): + """Returns a sentinel value. + + Indicates to a constructed type to set up its inner component so that it + can be referred to. This is useful in situation when you want to populate + descendants of a constructed type what requires being able to refer to + their parent types along the way. + + Example + ------- + + >>> constructed['record'] = setupComponent() + >>> constructed['record']['scalar'] = 42 + """ + return noValue + + class AbstractConstructedAsn1Item(Asn1ItemBase): + + #: If `True`, requires exact component type matching, + #: otherwise subtype relation is only enforced + strictConstraints = False + componentType = None - sizeSpec = constraint.ConstraintsIntersection() - def __init__(self, componentType=None, tagSet=None, - subtypeSpec=None, sizeSpec=None): - Asn1ItemBase.__init__(self, tagSet, subtypeSpec) - if componentType is None: - self._componentType = self.componentType - else: - self._componentType = componentType - if sizeSpec is None: - self._sizeSpec = self.sizeSpec - else: - self._sizeSpec = sizeSpec + sizeSpec = None + + def __init__(self, **kwargs): + readOnly = { + 'componentType': self.componentType, + 'sizeSpec': self.sizeSpec + } + readOnly.update(kwargs) + + Asn1ItemBase.__init__(self, **readOnly) + self._componentValues = [] - self._componentValuesSet = 0 def __repr__(self): - r = self.__class__.__name__ + '()' - for idx in range(len(self._componentValues)): - if self._componentValues[idx] is None: - continue - r = r + '.setComponentByPosition(%s, %r)' % ( - idx, self._componentValues[idx] - ) - return r + representation = [] + if self.componentType is not self.__class__.componentType: + representation.append('componentType=%r' % (self.componentType,)) + if self.tagSet is not self.__class__.tagSet: + representation.append('tagSet=%r' % (self.tagSet,)) + if self.subtypeSpec is not self.__class__.subtypeSpec: + representation.append('subtypeSpec=%r' % (self.subtypeSpec,)) + representation = '%s(%s)' % (self.__class__.__name__, ', '.join(representation)) + if self._componentValues: + for idx, component in enumerate(self._componentValues): + if component is None or component is noValue: + continue + representation += '.setComponentByPosition(%d, %s)' % (idx, repr(component)) + return representation def __eq__(self, other): return self is other and True or self._componentValues == other - def __ne__(self, other): return self._componentValues != other - def __lt__(self, other): return self._componentValues < other - def __le__(self, other): return self._componentValues <= other - def __gt__(self, other): return self._componentValues > other - def __ge__(self, other): return self._componentValues >= other + + def __ne__(self, other): + return self._componentValues != other + + def __lt__(self, other): + return self._componentValues < other + + def __le__(self, other): + return self._componentValues <= other + + def __gt__(self, other): + return self._componentValues > other + + def __ge__(self, other): + return self._componentValues >= other + if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._componentValues) + def __nonzero__(self): + return self._componentValues and True or False else: - def __bool__(self): return bool(self._componentValues) + def __bool__(self): + return self._componentValues and True or False - def getComponentTagMap(self): - raise error.PyAsn1Error('Method not implemented') + def _cloneComponentValues(self, myClone, cloneValueFlag): + pass - def _cloneComponentValues(self, myClone, cloneValueFlag): pass + def clone(self, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 size constraint(s) + + Returns + ------- + : + new instance of |ASN.1| type/value + + """ + cloneValueFlag = kwargs.pop('cloneValueFlag', False) + + initilaizers = self.readOnly.copy() + initilaizers.update(kwargs) + + clone = self.__class__(**initilaizers) - def clone(self, tagSet=None, subtypeSpec=None, sizeSpec=None, - cloneValueFlag=None): - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if sizeSpec is None: - sizeSpec = self._sizeSpec - r = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec) if cloneValueFlag: - self._cloneComponentValues(r, cloneValueFlag) - return r + self._cloneComponentValues(clone, cloneValueFlag) - def subtype(self, implicitTag=None, explicitTag=None, subtypeSpec=None, - sizeSpec=None, cloneValueFlag=None): + return clone + + def subtype(self, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 size constraint(s) + + Returns + ------- + : + new instance of |ASN.1| type/value + + """ + + initializers = self.readOnly.copy() + + cloneValueFlag = kwargs.pop('cloneValueFlag', False) + + implicitTag = kwargs.pop('implicitTag', None) if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - if sizeSpec is None: - sizeSpec = self._sizeSpec - else: - sizeSpec = sizeSpec + self._sizeSpec - r = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec) + initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) + + explicitTag = kwargs.pop('explicitTag', None) + if explicitTag is not None: + initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) + + for arg, option in kwargs.items(): + initializers[arg] += option + + clone = self.__class__(**initializers) + if cloneValueFlag: - self._cloneComponentValues(r, cloneValueFlag) - return r + self._cloneComponentValues(clone, cloneValueFlag) - def _verifyComponent(self, idx, value): pass + return clone - def verifySizeSpec(self): self._sizeSpec(self) + def verifySizeSpec(self): + self.sizeSpec(self) def getComponentByPosition(self, idx): raise error.PyAsn1Error('Method not implemented') + def setComponentByPosition(self, idx, value, verifyConstraints=True): raise error.PyAsn1Error('Method not implemented') - def getComponentType(self): return self._componentType + def setComponents(self, *args, **kwargs): + for idx, value in enumerate(args): + self[idx] = value + for k in kwargs: + self[k] = kwargs[k] + return self - def __getitem__(self, idx): return self.getComponentByPosition(idx) - def __setitem__(self, idx, value): self.setComponentByPosition(idx, value) + def __len__(self): + return len(self._componentValues) - def __len__(self): return len(self._componentValues) - def clear(self): self._componentValues = [] - self._componentValuesSet = 0 - def setDefaultComponents(self): pass + # backward compatibility + + def setDefaultComponents(self): + pass + + def getComponentType(self): + return self.componentType diff --git a/third_party/python/pyasn1/pyasn1/type/char.py b/third_party/python/pyasn1/pyasn1/type/char.py index ae112f8bd32f..60f9d97812e2 100644 --- a/third_party/python/pyasn1/pyasn1/type/char.py +++ b/third_party/python/pyasn1/pyasn1/type/char.py @@ -1,61 +1,374 @@ -# ASN.1 "character string" types +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys from pyasn1.type import univ, tag +from pyasn1 import error -class UTF8String(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) - ) - encoding = "utf-8" -class NumericString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( +__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString', + 'IA5String', 'GraphicString', 'VisibleString', 'ISO646String', + 'GeneralString', 'UniversalString', 'BMPString', 'UTF8String'] + +NoValue = univ.NoValue +noValue = univ.noValue + + +class AbstractCharacterString(univ.OctetString): + """Creates |ASN.1| type or 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. + + Parameters + ---------- + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + unicode object (Python 2) or string (Python 3), alternatively string + (Python 2) or bytes (Python 3) representing octet-stream of serialized + unicode string (note `encoding` parameter) or |ASN.1| class instance. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in octet-stream context. + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + """ + + if sys.version_info[0] <= 2: + def __str__(self): + try: + return self._value.encode(self.encoding) + except UnicodeEncodeError: + raise error.PyAsn1Error( + "Can't encode string '%s' with codec %s" % (self._value, self.encoding) + ) + + def __unicode__(self): + return unicode(self._value) + + def prettyIn(self, value): + try: + if isinstance(value, unicode): + return value + elif isinstance(value, str): + return value.decode(self.encoding) + elif isinstance(value, (tuple, list)): + return self.prettyIn(''.join([chr(x) for x in value])) + elif isinstance(value, univ.OctetString): + return value.asOctets().decode(self.encoding) + else: + return unicode(value) + + except (UnicodeDecodeError, LookupError): + raise error.PyAsn1Error( + "Can't decode string '%s' with codec %s" % (value, self.encoding) + ) + + def asOctets(self, padding=True): + return str(self) + + def asNumbers(self, padding=True): + return tuple([ord(x) for x in str(self)]) + + else: + def __str__(self): + return str(self._value) + + def __bytes__(self): + try: + return self._value.encode(self.encoding) + except UnicodeEncodeError: + raise error.PyAsn1Error( + "Can't encode string '%s' with codec %s" % (self._value, self.encoding) + ) + + def prettyIn(self, value): + try: + if isinstance(value, str): + return value + elif isinstance(value, bytes): + return value.decode(self.encoding) + elif isinstance(value, (tuple, list)): + return self.prettyIn(bytes(value)) + elif isinstance(value, univ.OctetString): + return value.asOctets().decode(self.encoding) + else: + return str(value) + + except (UnicodeDecodeError, LookupError): + raise error.PyAsn1Error( + "Can't decode string '%s' with codec %s" % (value, self.encoding) + ) + + def asOctets(self, padding=True): + return bytes(self) + + def asNumbers(self, padding=True): + return tuple(bytes(self)) + + def prettyOut(self, value): + return value + + def __reversed__(self): + return reversed(self._value) + + def clone(self, value=noValue, **kwargs): + """Creates a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + unicode object (Python 2) or string (Python 3), alternatively string + (Python 2) or bytes (Python 3) representing octet-stream of serialized + unicode string (note `encoding` parameter) or |ASN.1| class instance. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or + :py:class:`str` (Python 3) the payload when |ASN.1| object is used + in octet-stream context. + + Returns + ------- + : + new instance of |ASN.1| type/value + + """ + return univ.OctetString.clone(self, value, **kwargs) + + def subtype(self, value=noValue, **kwargs): + """Creates a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + unicode object (Python 2) or string (Python 3), alternatively string + (Python 2) or bytes (Python 3) representing octet-stream of serialized + unicode string (note `encoding` parameter) or |ASN.1| class instance. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or + :py:class:`str` (Python 3) the payload when |ASN.1| object is used + in octet-stream context. + + Returns + ------- + : + new instance of |ASN.1| type/value + + """ + return univ.OctetString.subtype(self, value, **kwargs) + +class NumericString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18) - ) + ) + encoding = 'us-ascii' -class PrintableString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class PrintableString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19) - ) + ) + encoding = 'us-ascii' -class TeletexString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class TeletexString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20) - ) - + ) + encoding = 'iso-8859-1' -class VideotexString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class T61String(TeletexString): + __doc__ = TeletexString.__doc__ + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class VideotexString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21) - ) + ) + encoding = 'iso-8859-1' -class IA5String(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class IA5String(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22) - ) + ) + encoding = 'us-ascii' -class GraphicString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class GraphicString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25) - ) + ) + encoding = 'iso-8859-1' -class VisibleString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class VisibleString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26) - ) + ) + encoding = 'us-ascii' -class GeneralString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class ISO646String(VisibleString): + __doc__ = VisibleString.__doc__ + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + +class GeneralString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27) - ) + ) + encoding = 'iso-8859-1' -class UniversalString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class UniversalString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28) - ) + ) encoding = "utf-32-be" -class BMPString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class BMPString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30) - ) + ) encoding = "utf-16-be" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class UTF8String(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) + ) + encoding = "utf-8" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() diff --git a/third_party/python/pyasn1/pyasn1/type/constraint.py b/third_party/python/pyasn1/pyasn1/type/constraint.py index 66873937d851..35bb0e24ee45 100644 --- a/third_party/python/pyasn1/pyasn1/type/constraint.py +++ b/third_party/python/pyasn1/pyasn1/type/constraint.py @@ -1,86 +1,124 @@ # -# ASN.1 subtype constraints classes. +# This file is part of pyasn1 software. # -# Constraints are relatively rare, but every ASN1 object -# is doing checks all the time for whether they have any -# constraints and whether they are applicable to the object. +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html # -# What we're going to do is define objects/functions that -# can be called unconditionally if they are present, and that -# are simply not present if there are no constraints. -# -# Original concept and code by Mike C. Fletcher. +# Original concept and code by Mike C. Fletcher. # import sys from pyasn1.type import error -class AbstractConstraint: +__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', 'ValueRangeConstraint', + 'ValueSizeConstraint', 'PermittedAlphabetConstraint', 'InnerTypeConstraint', + 'ConstraintsExclusion', 'ConstraintsIntersection', 'ConstraintsUnion'] + + +class AbstractConstraint(object): """Abstract base-class for constraint objects Constraints should be stored in a simple sequence in the - namespace of their client Asn1Item sub-classes. + namespace of their client Asn1Item sub-classes in cases + when ASN.1 constraint is define. """ + def __init__(self, *values): - self._valueMap = {} + self._valueMap = set() self._setValues(values) - self.__hashedValues = None + self.__hash = hash((self.__class__.__name__, self._values)) + def __call__(self, value, idx=None): + if not self._values: + return + try: self._testValue(value, idx) + except error.ValueConstraintError: raise error.ValueConstraintError( - '%s failed at: \"%s\"' % (self, sys.exc_info()[1]) + '%s failed at: %r' % (self, sys.exc_info()[1]) ) + def __repr__(self): return '%s(%s)' % ( self.__class__.__name__, ', '.join([repr(x) for x in self._values]) ) + def __eq__(self, other): return self is other and True or self._values == other - def __ne__(self, other): return self._values != other - def __lt__(self, other): return self._values < other - def __le__(self, other): return self._values <= other - def __gt__(self, other): return self._values > other - def __ge__(self, other): return self._values >= other + + def __ne__(self, other): + return self._values != other + + def __lt__(self, other): + return self._values < other + + def __le__(self, other): + return self._values <= other + + def __gt__(self, other): + return self._values > other + + def __ge__(self, other): + return self._values >= other + if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._values) + def __nonzero__(self): + return self._values and True or False else: - def __bool__(self): return bool(self._values) + def __bool__(self): + return self._values and True or False def __hash__(self): - if self.__hashedValues is None: - self.__hashedValues = hash((self.__class__.__name__, self._values)) - return self.__hashedValues + return self.__hash + + def _setValues(self, values): + self._values = values - def _setValues(self, values): self._values = values def _testValue(self, value, idx): raise error.ValueConstraintError(value) # Constraints derivation logic - def getValueMap(self): return self._valueMap + def getValueMap(self): + return self._valueMap + def isSuperTypeOf(self, otherConstraint): - return self in otherConstraint.getValueMap() or \ - otherConstraint is self or otherConstraint == self + # TODO: fix possible comparison of set vs scalars here + return (otherConstraint is self or + not self._values or + otherConstraint == self or + self in otherConstraint.getValueMap()) + def isSubTypeOf(self, otherConstraint): - return otherConstraint in self._valueMap or \ - otherConstraint is self or otherConstraint == self + return (otherConstraint is self or + not self or + otherConstraint == self or + otherConstraint in self._valueMap) class SingleValueConstraint(AbstractConstraint): """Value must be part of defined values constraint""" + + def _setValues(self, values): + self._values = values + self._set = set(values) + def _testValue(self, value, idx): - # XXX index vals for performance? - if value not in self._values: + if value not in self._set: raise error.ValueConstraintError(value) + class ContainedSubtypeConstraint(AbstractConstraint): """Value must satisfy all of defined set of constraints""" + def _testValue(self, value, idx): for c in self._values: c(value, idx) + class ValueRangeConstraint(AbstractConstraint): """Value must be within start and stop values (inclusive)""" + def _testValue(self, value, idx): if value < self.start or value > self.stop: raise error.ValueConstraintError(value) @@ -89,7 +127,7 @@ class ValueRangeConstraint(AbstractConstraint): if len(values) != 2: raise error.PyAsn1Error( '%s: bad constraint values' % (self.__class__.__name__,) - ) + ) self.start, self.stop = values if self.start > self.stop: raise error.PyAsn1Error( @@ -99,28 +137,31 @@ class ValueRangeConstraint(AbstractConstraint): ) ) AbstractConstraint._setValues(self, values) - + + class ValueSizeConstraint(ValueRangeConstraint): """len(value) must be within start and stop values (inclusive)""" + def _testValue(self, value, idx): - l = len(value) - if l < self.start or l > self.stop: + valueSize = len(value) + if valueSize < self.start or valueSize > self.stop: raise error.ValueConstraintError(value) + class PermittedAlphabetConstraint(SingleValueConstraint): def _setValues(self, values): - self._values = () - for v in values: - self._values = self._values + tuple(v) + self._values = values + self._set = set(values) def _testValue(self, value, idx): - for v in value: - if v not in self._values: - raise error.ValueConstraintError(value) + if not self._set.issuperset(value): + raise error.ValueConstraintError(value) -# This is a bit kludgy, meaning two op modes within a single constraing + +# This is a bit kludgy, meaning two op modes within a single constraint class InnerTypeConstraint(AbstractConstraint): """Value must satisfy type and presense constraints""" + def _testValue(self, value, idx): if self.__singleTypeConstraint: self.__singleTypeConstraint(value) @@ -128,7 +169,7 @@ class InnerTypeConstraint(AbstractConstraint): if idx not in self.__multipleTypeConstraint: raise error.ValueConstraintError(value) constraint, status = self.__multipleTypeConstraint[idx] - if status == 'ABSENT': # XXX presense is not checked! + if status == 'ABSENT': # XXX presense is not checked! raise error.ValueConstraintError(value) constraint(value) @@ -142,10 +183,12 @@ class InnerTypeConstraint(AbstractConstraint): self.__singleTypeConstraint = v AbstractConstraint._setValues(self, values) -# Boolean ops on constraints + +# Boolean ops on constraints class ConstraintsExclusion(AbstractConstraint): """Value must not fit the single constraint""" + def _testValue(self, value, idx): try: self._values[0](value, idx) @@ -159,42 +202,57 @@ class ConstraintsExclusion(AbstractConstraint): raise error.PyAsn1Error('Single constraint expected') AbstractConstraint._setValues(self, values) + class AbstractConstraintSet(AbstractConstraint): """Value must not satisfy the single constraint""" - def __getitem__(self, idx): return self._values[idx] - def __add__(self, value): return self.__class__(self, value) - def __radd__(self, value): return self.__class__(self, value) + def __getitem__(self, idx): + return self._values[idx] - def __len__(self): return len(self._values) + def __iter__(self): + return iter(self._values) + + def __add__(self, value): + return self.__class__(*(self._values + (value,))) + + def __radd__(self, value): + return self.__class__(*((value,) + self._values)) + + def __len__(self): + return len(self._values) # Constraints inclusion in sets - + def _setValues(self, values): self._values = values - for v in values: - self._valueMap[v] = 1 - self._valueMap.update(v.getValueMap()) + for constraint in values: + if constraint: + self._valueMap.add(constraint) + self._valueMap.update(constraint.getValueMap()) + class ConstraintsIntersection(AbstractConstraintSet): """Value must satisfy all constraints""" + def _testValue(self, value, idx): - for v in self._values: - v(value, idx) + for constraint in self._values: + constraint(value, idx) + class ConstraintsUnion(AbstractConstraintSet): """Value must satisfy at least one constraint""" + def _testValue(self, value, idx): - for v in self._values: + for constraint in self._values: try: - v(value, idx) + constraint(value, idx) except error.ValueConstraintError: pass else: return raise error.ValueConstraintError( 'all of %s failed for \"%s\"' % (self._values, value) - ) + ) # XXX # add tests for type check diff --git a/third_party/python/pyasn1/pyasn1/type/error.py b/third_party/python/pyasn1/pyasn1/type/error.py index 3e6848447251..cbfa276a8d0a 100644 --- a/third_party/python/pyasn1/pyasn1/type/error.py +++ b/third_party/python/pyasn1/pyasn1/type/error.py @@ -1,3 +1,11 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1.error import PyAsn1Error -class ValueConstraintError(PyAsn1Error): pass + +class ValueConstraintError(PyAsn1Error): + pass diff --git a/third_party/python/pyasn1/pyasn1/type/namedtype.py b/third_party/python/pyasn1/pyasn1/type/namedtype.py index 48967a5fe223..7a51f18624da 100644 --- a/third_party/python/pyasn1/pyasn1/type/namedtype.py +++ b/third_party/python/pyasn1/pyasn1/type/namedtype.py @@ -1,132 +1,511 @@ -# NamedType specification for constructed types +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# import sys -from pyasn1.type import tagmap +from pyasn1.type import tag, tagmap from pyasn1 import error -class NamedType: - isOptional = 0 - isDefaulted = 0 - def __init__(self, name, t): - self.__name = name; self.__type = t - def __repr__(self): return '%s(%s, %s)' % ( - self.__class__.__name__, self.__name, self.__type - ) - def getType(self): return self.__type - def getName(self): return self.__name - def __getitem__(self, idx): - if idx == 0: return self.__name - if idx == 1: return self.__type - raise IndexError() - -class OptionalNamedType(NamedType): - isOptional = 1 -class DefaultedNamedType(NamedType): - isDefaulted = 1 - -class NamedTypes: - def __init__(self, *namedTypes): - self.__namedTypes = namedTypes - self.__namedTypesLen = len(self.__namedTypes) - self.__minTagSet = None - self.__tagToPosIdx = {}; self.__nameToPosIdx = {} - self.__tagMap = { False: None, True: None } - self.__ambigiousTypes = {} +__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType', 'NamedTypes'] + + +class NamedType(object): + """Create named field object for a constructed ASN.1 type. + + The |NamedType| object represents a single name and ASN.1 type of a constructed ASN.1 type. + + |NamedType| objects are immutable and duck-type Python :class:`tuple` objects + holding *name* and *asn1Object* components. + + Parameters + ---------- + name: :py:class:`str` + Field name + + asn1Object: + ASN.1 type object + """ + isOptional = False + isDefaulted = False + + def __init__(self, name, asn1Object): + self.__name = name + self.__type = asn1Object + self.__nameAndType = name, asn1Object def __repr__(self): - r = '%s(' % self.__class__.__name__ - for n in self.__namedTypes: - r = r + '%r, ' % (n,) - return r + ')' + return '%s(%r, %r)' % (self.__class__.__name__, self.__name, self.__type) + + def __eq__(self, other): + return self.__nameAndType == other + + def __ne__(self, other): + return self.__nameAndType != other + + def __lt__(self, other): + return self.__nameAndType < other + + def __le__(self, other): + return self.__nameAndType <= other + + def __gt__(self, other): + return self.__nameAndType > other + + def __ge__(self, other): + return self.__nameAndType >= other + + def __hash__(self): + return hash(self.__nameAndType) + + def __getitem__(self, idx): + return self.__nameAndType[idx] + + def __iter__(self): + return iter(self.__nameAndType) + + @property + def name(self): + return self.__name - def __getitem__(self, idx): return self.__namedTypes[idx] + @property + def asn1Object(self): + return self.__type + + # Backward compatibility + + def getName(self): + return self.name + + def getType(self): + return self.asn1Object + + +class OptionalNamedType(NamedType): + __doc__ = NamedType.__doc__ + + isOptional = True + + +class DefaultedNamedType(NamedType): + __doc__ = NamedType.__doc__ + + isDefaulted = True + + +class NamedTypes(object): + """Create a collection of named fields for a constructed ASN.1 type. + + The NamedTypes object represents a collection of named fields of a constructed ASN.1 type. + + *NamedTypes* objects are immutable and duck-type Python :class:`dict` objects + holding *name* as keys and ASN.1 type object as values. + + Parameters + ---------- + *namedTypes: :class:`~pyasn1.type.namedtype.NamedType` + """ + def __init__(self, *namedTypes, **kwargs): + self.__namedTypes = namedTypes + self.__namedTypesLen = len(self.__namedTypes) + self.__minTagSet = self.__computeMinTagSet() + self.__nameToPosMap = self.__computeNameToPosMap() + self.__tagToPosMap = self.__computeTagToPosMap() + self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {} + self.__uniqueTagMap = self.__computeTagMaps(unique=True) + self.__nonUniqueTagMap = self.__computeTagMaps(unique=False) + self.__hasOptionalOrDefault = bool([True for namedType in self.__namedTypes + if namedType.isDefaulted or namedType.isOptional]) + self.__requiredComponents = frozenset( + [idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted] + ) + self.__keys = frozenset([namedType.name for namedType in self.__namedTypes]) + self.__values = tuple([namedType.asn1Object for namedType in self.__namedTypes]) + self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes]) + + def __repr__(self): + return '%s(%s)' % ( + self.__class__.__name__, ', '.join([repr(x) for x in self.__namedTypes]) + ) + + def __eq__(self, other): + return self.__namedTypes == other + + def __ne__(self, other): + return self.__namedTypes != other + + def __lt__(self, other): + return self.__namedTypes < other + + def __le__(self, other): + return self.__namedTypes <= other + + def __gt__(self, other): + return self.__namedTypes > other + + def __ge__(self, other): + return self.__namedTypes >= other + + def __hash__(self): + return hash(self.__namedTypes) + + def __getitem__(self, idx): + try: + return self.__namedTypes[idx] + + except TypeError: + return self.__namedTypes[self.__nameToPosMap[idx]] + + def __contains__(self, key): + return key in self.__nameToPosMap + + def __iter__(self): + return (x[0] for x in self.__namedTypes) if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self.__namedTypesLen) + def __nonzero__(self): + return self.__namedTypesLen > 0 else: - def __bool__(self): return bool(self.__namedTypesLen) - def __len__(self): return self.__namedTypesLen - - def getTypeByPosition(self, idx): - if idx < 0 or idx >= self.__namedTypesLen: - raise error.PyAsn1Error('Type position out of range') - else: - return self.__namedTypes[idx].getType() + def __bool__(self): + return self.__namedTypesLen > 0 - def getPositionByType(self, tagSet): - if not self.__tagToPosIdx: - idx = self.__namedTypesLen - while idx > 0: - idx = idx - 1 - tagMap = self.__namedTypes[idx].getType().getTagMap() - for t in tagMap.getPosMap(): - if t in self.__tagToPosIdx: - raise error.PyAsn1Error('Duplicate type %s' % (t,)) - self.__tagToPosIdx[t] = idx + def __len__(self): + return self.__namedTypesLen + + # Python dict protocol + + def values(self): + return self.__values + + def keys(self): + return self.__keys + + def items(self): + return self.__items + + def clone(self): + return self.__class__(*self.__namedTypes) + + class PostponedError(object): + def __init__(self, errorMsg): + self.__errorMsg = errorMsg + + def __getitem__(self, item): + raise error.PyAsn1Error(self.__errorMsg) + + def __computeTagToPosMap(self): + tagToPosMap = {} + for idx, namedType in enumerate(self.__namedTypes): + tagMap = namedType.asn1Object.tagMap + if isinstance(tagMap, NamedTypes.PostponedError): + return tagMap + if not tagMap: + continue + for _tagSet in tagMap.presentTypes: + if _tagSet in tagToPosMap: + return NamedTypes.PostponedError('Duplicate component tag %s at %s' % (_tagSet, namedType)) + tagToPosMap[_tagSet] = idx + + return tagToPosMap + + def __computeNameToPosMap(self): + nameToPosMap = {} + for idx, namedType in enumerate(self.__namedTypes): + if namedType.name in nameToPosMap: + return NamedTypes.PostponedError('Duplicate component name %s at %s' % (namedType.name, namedType)) + nameToPosMap[namedType.name] = idx + + return nameToPosMap + + def __computeAmbiguousTypes(self): + ambigiousTypes = {} + partialAmbigiousTypes = () + for idx, namedType in reversed(tuple(enumerate(self.__namedTypes))): + if namedType.isOptional or namedType.isDefaulted: + partialAmbigiousTypes = (namedType,) + partialAmbigiousTypes + else: + partialAmbigiousTypes = (namedType,) + if len(partialAmbigiousTypes) == len(self.__namedTypes): + ambigiousTypes[idx] = self + else: + ambigiousTypes[idx] = NamedTypes(*partialAmbigiousTypes, **dict(terminal=True)) + return ambigiousTypes + + def getTypeByPosition(self, idx): + """Return ASN.1 type object by its position in fields set. + + Parameters + ---------- + idx: :py:class:`int` + Field index + + Returns + ------- + : + ASN.1 type + + Raises + ------ + : :class:`~pyasn1.error.PyAsn1Error` + If given position is out of fields range + """ try: - return self.__tagToPosIdx[tagSet] - except KeyError: - raise error.PyAsn1Error('Type %s not found' % (tagSet,)) - - def getNameByPosition(self, idx): - try: - return self.__namedTypes[idx].getName() + return self.__namedTypes[idx].asn1Object + except IndexError: raise error.PyAsn1Error('Type position out of range') - def getPositionByName(self, name): - if not self.__nameToPosIdx: - idx = self.__namedTypesLen - while idx > 0: - idx = idx - 1 - n = self.__namedTypes[idx].getName() - if n in self.__nameToPosIdx: - raise error.PyAsn1Error('Duplicate name %s' % (n,)) - self.__nameToPosIdx[n] = idx + + def getPositionByType(self, tagSet): + """Return field position by its ASN.1 type. + + Parameters + ---------- + tagSet: :class:`~pysnmp.type.tag.TagSet` + ASN.1 tag set distinguishing one ASN.1 type from others. + + Returns + ------- + : :py:class:`int` + ASN.1 type position in fields set + + Raises + ------ + : :class:`~pyasn1.error.PyAsn1Error` + If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes* + """ try: - return self.__nameToPosIdx[name] + return self.__tagToPosMap[tagSet] + + except KeyError: + raise error.PyAsn1Error('Type %s not found' % (tagSet,)) + + def getNameByPosition(self, idx): + """Return field name by its position in fields set. + + Parameters + ---------- + idx: :py:class:`idx` + Field index + + Returns + ------- + : :py:class:`str` + Field name + + Raises + ------ + : :class:`~pyasn1.error.PyAsn1Error` + If given field name is not present in callee *NamedTypes* + """ + try: + return self.__namedTypes[idx].name + + except IndexError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByName(self, name): + """Return field position by filed name. + + Parameters + ---------- + name: :py:class:`str` + Field name + + Returns + ------- + : :py:class:`int` + Field position in fields set + + Raises + ------ + : :class:`~pyasn1.error.PyAsn1Error` + If *name* is not present or not unique within callee *NamedTypes* + """ + try: + return self.__nameToPosMap[name] + except KeyError: raise error.PyAsn1Error('Name %s not found' % (name,)) - def __buildAmbigiousTagMap(self): - ambigiousTypes = () - idx = self.__namedTypesLen - while idx > 0: - idx = idx - 1 - t = self.__namedTypes[idx] - if t.isOptional or t.isDefaulted: - ambigiousTypes = (t, ) + ambigiousTypes - else: - ambigiousTypes = (t, ) - self.__ambigiousTypes[idx] = NamedTypes(*ambigiousTypes) - def getTagMapNearPosition(self, idx): - if not self.__ambigiousTypes: self.__buildAmbigiousTagMap() + """Return ASN.1 types that are allowed at or past given field position. + + Some ASN.1 serialization allow for skipping optional and defaulted fields. + Some constructed ASN.1 types allow reordering of the fields. When recovering + such objects it may be important to know which types can possibly be + present at any given position in the field sets. + + Parameters + ---------- + idx: :py:class:`int` + Field index + + Returns + ------- + : :class:`~pyasn1.type.tagmap.TagMap` + Map if ASN.1 types allowed at given field position + + Raises + ------ + : :class:`~pyasn1.error.PyAsn1Error` + If given position is out of fields range + """ try: - return self.__ambigiousTypes[idx].getTagMap() + return self.__ambiguousTypes[idx].tagMap + except KeyError: raise error.PyAsn1Error('Type position out of range') def getPositionNearType(self, tagSet, idx): - if not self.__ambigiousTypes: self.__buildAmbigiousTagMap() + """Return the closest field position where given ASN.1 type is allowed. + + Some ASN.1 serialization allow for skipping optional and defaulted fields. + Some constructed ASN.1 types allow reordering of the fields. When recovering + such objects it may be important to know at which field position, in field set, + given *tagSet* is allowed at or past *idx* position. + + Parameters + ---------- + tagSet: :class:`~pyasn1.type.tag.TagSet` + ASN.1 type which field position to look up + + idx: :py:class:`int` + Field position at or past which to perform ASN.1 type look up + + Returns + ------- + : :py:class:`int` + Field position in fields set + + Raises + ------ + : :class:`~pyasn1.error.PyAsn1Error` + If *tagSet* is not present or not unique within callee *NamedTypes* + or *idx* is out of fields range + """ try: - return idx+self.__ambigiousTypes[idx].getPositionByType(tagSet) + return idx + self.__ambiguousTypes[idx].getPositionByType(tagSet) + except KeyError: raise error.PyAsn1Error('Type position out of range') - def genMinTagSet(self): - if self.__minTagSet is None: - for t in self.__namedTypes: - __type = t.getType() - tagSet = getattr(__type,'getMinTagSet',__type.getTagSet)() - if self.__minTagSet is None or tagSet < self.__minTagSet: - self.__minTagSet = tagSet + def __computeMinTagSet(self): + minTagSet = None + for namedType in self.__namedTypes: + asn1Object = namedType.asn1Object + + try: + tagSet = asn1Object.minTagSet + + except AttributeError: + tagSet = asn1Object.tagSet + + if minTagSet is None or tagSet < minTagSet: + minTagSet = tagSet + + return minTagSet or tag.TagSet() + + @property + def minTagSet(self): + """Return the minimal TagSet among ASN.1 type in callee *NamedTypes*. + + Some ASN.1 types/serialization protocols require ASN.1 types to be + arranged based on their numerical tag value. The *minTagSet* property + returns that. + + Returns + ------- + : :class:`~pyasn1.type.tagset.TagSet` + Minimal TagSet among ASN.1 types in callee *NamedTypes* + """ return self.__minTagSet - - def getTagMap(self, uniq=False): - if self.__tagMap[uniq] is None: - tagMap = tagmap.TagMap() - for nt in self.__namedTypes: - tagMap = tagMap.clone( - nt.getType(), nt.getType().getTagMap(), uniq - ) - self.__tagMap[uniq] = tagMap - return self.__tagMap[uniq] + + def __computeTagMaps(self, unique): + presentTypes = {} + skipTypes = {} + defaultType = None + for namedType in self.__namedTypes: + tagMap = namedType.asn1Object.tagMap + if isinstance(tagMap, NamedTypes.PostponedError): + return tagMap + for tagSet in tagMap: + if unique and tagSet in presentTypes: + return NamedTypes.PostponedError('Non-unique tagSet %s of %s at %s' % (tagSet, namedType, self)) + presentTypes[tagSet] = namedType.asn1Object + skipTypes.update(tagMap.skipTypes) + + if defaultType is None: + defaultType = tagMap.defaultType + elif tagMap.defaultType is not None: + return NamedTypes.PostponedError('Duplicate default ASN.1 type at %s' % (self,)) + + return tagmap.TagMap(presentTypes, skipTypes, defaultType) + + @property + def tagMap(self): + """Return a *TagMap* object from tags and types recursively. + + Return a :class:`~pyasn1.type.tagmap.TagMap` object by + combining tags from *TagMap* objects of children types and + associating them with their immediate child type. + + Example + ------- + + .. code-block:: python + + OuterType ::= CHOICE { + innerType INTEGER + } + + Calling *.tagMap* on *OuterType* will yield a map like this: + + .. code-block:: python + + Integer.tagSet -> Choice + """ + return self.__nonUniqueTagMap + + @property + def tagMapUnique(self): + """Return a *TagMap* object from unique tags and types recursively. + + Return a :class:`~pyasn1.type.tagmap.TagMap` object by + combining tags from *TagMap* objects of children types and + associating them with their immediate child type. + + Example + ------- + + .. code-block:: python + + OuterType ::= CHOICE { + innerType INTEGER + } + + Calling *.tagMapUnique* on *OuterType* will yield a map like this: + + .. code-block:: python + + Integer.tagSet -> Choice + + Note + ---- + + Duplicate *TagSet* objects found in the tree of children + types would cause error. + """ + return self.__uniqueTagMap + + @property + def hasOptionalOrDefault(self): + return self.__hasOptionalOrDefault + + @property + def namedTypes(self): + return iter(self.__namedTypes) + + @property + def requiredComponents(self): + return self.__requiredComponents diff --git a/third_party/python/pyasn1/pyasn1/type/namedval.py b/third_party/python/pyasn1/pyasn1/type/namedval.py index d0fea7cc7cbc..008ddc0462af 100644 --- a/third_party/python/pyasn1/pyasn1/type/namedval.py +++ b/third_party/python/pyasn1/pyasn1/type/namedval.py @@ -1,46 +1,181 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# # ASN.1 named integers +# from pyasn1 import error -__all__ = [ 'NamedValues' ] +__all__ = ['NamedValues'] + + +class NamedValues(object): + """Create named values object. + + The |NamedValues| object represents a collection of string names + associated with numeric IDs. These objects are used for giving + names to otherwise numerical values. + + |NamedValues| objects are immutable and duck-type Python + :class:`dict` object mapping ID to name and vice-versa. + + Parameters + ---------- + + \*args: variable number of two-element :py:class:`tuple` + \*\*kwargs: keyword parameters of: + + name: :py:class:`str` + Value name + + value: :py:class:`int` + A numerical value + + Examples + -------- + + >>> nv = namedval.NamedValues('a', 'b', ('c', 0), d=1) + >>> nv + >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3} + >>> nv[0] + 'c' + >>> nv['a'] + 2 + """ + def __init__(self, *args, **kwargs): + self.__names = {} + self.__numbers = {} + + anonymousNames = [] + + for namedValue in args: + if isinstance(namedValue, (tuple, list)): + try: + name, number = namedValue + + except ValueError: + raise error.PyAsn1Error('Not a proper attribute-value pair %r' % (namedValue,)) -class NamedValues: - def __init__(self, *namedValues): - self.nameToValIdx = {}; self.valToNameIdx = {} - self.namedValues = () - automaticVal = 1 - for namedValue in namedValues: - if isinstance(namedValue, tuple): - name, val = namedValue else: - name = namedValue - val = automaticVal - if name in self.nameToValIdx: - raise error.PyAsn1Error('Duplicate name %s' % (name,)) - self.nameToValIdx[name] = val - if val in self.valToNameIdx: - raise error.PyAsn1Error('Duplicate value %s=%s' % (name, val)) - self.valToNameIdx[val] = name - self.namedValues = self.namedValues + ((name, val),) - automaticVal = automaticVal + 1 - def __str__(self): return str(self.namedValues) - - def getName(self, value): - if value in self.valToNameIdx: - return self.valToNameIdx[value] + anonymousNames.append(namedValue) + continue - def getValue(self, name): - if name in self.nameToValIdx: - return self.nameToValIdx[name] - - def __getitem__(self, i): return self.namedValues[i] - def __len__(self): return len(self.namedValues) + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + if number in self.__numbers: + raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) + + self.__names[name] = number + self.__numbers[number] = name + + for name, number in kwargs.items(): + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + if number in self.__numbers: + raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) + + self.__names[name] = number + self.__numbers[number] = name + + if anonymousNames: + + number = self.__numbers and max(self.__numbers) + 1 or 0 + + for name in anonymousNames: + + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + self.__names[name] = number + self.__numbers[number] = name + + number += 1 + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, tuple(self.items())) + + def __str__(self): + return str(self.items()) + + def __eq__(self, other): + return dict(self) == other + + def __ne__(self, other): + return dict(self) != other + + def __lt__(self, other): + return dict(self) < other + + def __le__(self, other): + return dict(self) <= other + + def __gt__(self, other): + return dict(self) > other + + def __ge__(self, other): + return dict(self) >= other + + def __hash__(self): + return hash(self.items()) + + # Python dict protocol (read-only) + + def __getitem__(self, key): + try: + return self.__numbers[key] + + except KeyError: + return self.__names[key] + + def __len__(self): + return len(self.__names) + + def __contains__(self, key): + return key in self.__names or key in self.__numbers + + def __iter__(self): + return iter(self.__names) + + def values(self): + return iter(self.__numbers) + + def keys(self): + return iter(self.__names) + + def items(self): + for name in self.__names: + yield name, self.__names[name] + + # support merging def __add__(self, namedValues): - return self.__class__(*self.namedValues + namedValues) - def __radd__(self, namedValues): - return self.__class__(*namedValues + tuple(self)) - - def clone(self, *namedValues): - return self.__class__(*tuple(self) + namedValues) + return self.__class__(*tuple(self.items()) + tuple(namedValues.items())) -# XXX clone/subtype? + # XXX clone/subtype? + + def clone(self, *args, **kwargs): + new = self.__class__(*args, **kwargs) + return self + new + + # legacy protocol + + def getName(self, value): + if value in self.__numbers: + return self.__numbers[value] + + def getValue(self, name): + if name in self.__names: + return self.__names[name] + + def getValues(self, *names): + try: + return [self.__names[name] for name in names] + + except KeyError: + raise error.PyAsn1Error( + 'Unknown bit identifier(s): %s' % (set(names).difference(self.__names),) + ) diff --git a/third_party/python/pyasn1/pyasn1/type/tag.py b/third_party/python/pyasn1/pyasn1/type/tag.py index 1144907fa153..6c0e2c17b0b5 100644 --- a/third_party/python/pyasn1/pyasn1/type/tag.py +++ b/third_party/python/pyasn1/pyasn1/type/tag.py @@ -1,122 +1,318 @@ -# ASN.1 types tags -from operator import getitem +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1 import error +__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext', + 'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed', + 'tagCategoryImplicit', 'tagCategoryExplicit', 'tagCategoryUntagged', + 'Tag', 'TagSet'] + +#: Identifier for ASN.1 class UNIVERSAL tagClassUniversal = 0x00 + +#: Identifier for ASN.1 class APPLICATION tagClassApplication = 0x40 + +#: Identifier for ASN.1 class context-specific tagClassContext = 0x80 + +#: Identifier for ASN.1 class private tagClassPrivate = 0xC0 +#: Identifier for "simple" ASN.1 structure (e.g. scalar) tagFormatSimple = 0x00 + +#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components) tagFormatConstructed = 0x20 tagCategoryImplicit = 0x01 tagCategoryExplicit = 0x02 tagCategoryUntagged = 0x04 -class Tag: + +class Tag(object): + """Create ASN.1 tag + + Represents ASN.1 tag that can be attached to a ASN.1 type to make + types distinguishable from each other. + + *Tag* objects are immutable and duck-type Python :class:`tuple` objects + holding three integer components of a tag. + + Parameters + ---------- + tagClass: :py:class:`int` + Tag *class* value + + tagFormat: :py:class:`int` + Tag *format* value + + tagId: :py:class:`int` + Tag ID value + """ def __init__(self, tagClass, tagFormat, tagId): if tagId < 0: - raise error.PyAsn1Error( - 'Negative tag ID (%s) not allowed' % (tagId,) - ) - self.__tag = (tagClass, tagFormat, tagId) - self.uniq = (tagClass, tagId) - self.__hashedUniqTag = hash(self.uniq) + raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId) + self.__tagClass = tagClass + self.__tagFormat = tagFormat + self.__tagId = tagId + self.__tagClassId = tagClass, tagId + self.__hash = hash(self.__tagClassId) + + def __str__(self): + return '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId) def __repr__(self): return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % ( - (self.__class__.__name__,) + self.__tag - ) - # These is really a hotspot -- expose public "uniq" attribute to save on - # function calls - def __eq__(self, other): return self.uniq == other.uniq - def __ne__(self, other): return self.uniq != other.uniq - def __lt__(self, other): return self.uniq < other.uniq - def __le__(self, other): return self.uniq <= other.uniq - def __gt__(self, other): return self.uniq > other.uniq - def __ge__(self, other): return self.uniq >= other.uniq - def __hash__(self): return self.__hashedUniqTag - def __getitem__(self, idx): return self.__tag[idx] + (self.__class__.__name__, self.__tagClass, self.__tagFormat, self.__tagId) + ) + + def __eq__(self, other): + return self.__tagClassId == other + + def __ne__(self, other): + return self.__tagClassId != other + + def __lt__(self, other): + return self.__tagClassId < other + + def __le__(self, other): + return self.__tagClassId <= other + + def __gt__(self, other): + return self.__tagClassId > other + + def __ge__(self, other): + return self.__tagClassId >= other + + def __hash__(self): + return self.__hash + + def __getitem__(self, idx): + if idx == 0: + return self.__tagClass + elif idx == 1: + return self.__tagFormat + elif idx == 2: + return self.__tagId + else: + raise IndexError() + + def __iter__(self): + yield self.__tagClass + yield self.__tagFormat + yield self.__tagId + def __and__(self, otherTag): - (tagClass, tagFormat, tagId) = otherTag - return self.__class__( - self.__tag&tagClass, self.__tag&tagFormat, self.__tag&tagId - ) + return self.__class__(self.__tagClass & otherTag.tagClass, + self.__tagFormat & otherTag.tagFormat, + self.__tagId & otherTag.tagId) + def __or__(self, otherTag): - (tagClass, tagFormat, tagId) = otherTag - return self.__class__( - self.__tag[0]|tagClass, - self.__tag[1]|tagFormat, - self.__tag[2]|tagId - ) - def asTuple(self): return self.__tag # __getitem__() is slow - -class TagSet: + return self.__class__(self.__tagClass | otherTag.tagClass, + self.__tagFormat | otherTag.tagFormat, + self.__tagId | otherTag.tagId) + + @property + def tagClass(self): + """ASN.1 tag class + + Returns + ------- + : :py:class:`int` + Tag class + """ + return self.__tagClass + + @property + def tagFormat(self): + """ASN.1 tag format + + Returns + ------- + : :py:class:`int` + Tag format + """ + return self.__tagFormat + + @property + def tagId(self): + """ASN.1 tag ID + + Returns + ------- + : :py:class:`int` + Tag ID + """ + return self.__tagId + + +class TagSet(object): + """Create a collection of ASN.1 tags + + Represents a combination of :class:`~pyasn1.type.tag.Tag` objects + that can be attached to a ASN.1 type to make types distinguishable + from each other. + + *TagSet* objects are immutable and duck-type Python :class:`tuple` objects + holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects. + + Parameters + ---------- + baseTag: :class:`~pyasn1.type.tag.Tag` + Base *Tag* object. This tag survives IMPLICIT tagging. + + *superTags: :class:`~pyasn1.type.tag.Tag` + Additional *Tag* objects taking part in subtyping. + """ def __init__(self, baseTag=(), *superTags): self.__baseTag = baseTag self.__superTags = superTags - self.__hashedSuperTags = hash(superTags) - _uniq = () - for t in superTags: - _uniq = _uniq + t.uniq - self.uniq = _uniq + self.__superTagsClassId = tuple( + [(superTag.tagClass, superTag.tagId) for superTag in superTags] + ) self.__lenOfSuperTags = len(superTags) - + self.__hash = hash(self.__superTagsClassId) + + def __str__(self): + return self.__superTags and '+'.join([str(x) for x in self.__superTags]) or '[untagged]' + def __repr__(self): return '%s(%s)' % ( - self.__class__.__name__, - ', '.join([repr(x) for x in self.__superTags]) - ) + self.__class__.__name__, '(), ' + ', '.join([repr(x) for x in self.__superTags]) + ) def __add__(self, superTag): - return self.__class__( - self.__baseTag, *self.__superTags + (superTag,) - ) + return self.__class__(self.__baseTag, *self.__superTags + (superTag,)) + def __radd__(self, superTag): - return self.__class__( - self.__baseTag, *(superTag,) + self.__superTags - ) + return self.__class__(self.__baseTag, *(superTag,) + self.__superTags) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.__class__(self.__baseTag, *self.__superTags[i]) + else: + return self.__superTags[i] + + def __eq__(self, other): + return self.__superTagsClassId == other + + def __ne__(self, other): + return self.__superTagsClassId != other + + def __lt__(self, other): + return self.__superTagsClassId < other + + def __le__(self, other): + return self.__superTagsClassId <= other + + def __gt__(self, other): + return self.__superTagsClassId > other + + def __ge__(self, other): + return self.__superTagsClassId >= other + + def __hash__(self): + return self.__hash + + def __len__(self): + return self.__lenOfSuperTags + + @property + def baseTag(self): + """Return base ASN.1 tag + + Returns + ------- + : :class:`~pyasn1.type.tag.Tag` + Base tag of this *TagSet* + """ + return self.__baseTag + + @property + def superTags(self): + """Return ASN.1 tags + + Returns + ------- + : :py:class:`tuple` + Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains + """ + return self.__superTags def tagExplicitly(self, superTag): - tagClass, tagFormat, tagId = superTag - if tagClass == tagClassUniversal: - raise error.PyAsn1Error( - 'Can\'t tag with UNIVERSAL-class tag' - ) - if tagFormat != tagFormatConstructed: - superTag = Tag(tagClass, tagFormatConstructed, tagId) + """Return explicitly tagged *TagSet* + + Create a new *TagSet* representing callee *TagSet* explicitly tagged + with passed tag(s). With explicit tagging mode, new tags are appended + to existing tag(s). + + Parameters + ---------- + superTag: :class:`~pyasn1.type.tag.Tag` + *Tag* object to tag this *TagSet* + + Returns + ------- + : :class:`~pyasn1.type.tag.TagSet` + New *TagSet* object + """ + if superTag.tagClass == tagClassUniversal: + raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag") + if superTag.tagFormat != tagFormatConstructed: + superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId) return self + superTag def tagImplicitly(self, superTag): - tagClass, tagFormat, tagId = superTag + """Return implicitly tagged *TagSet* + + Create a new *TagSet* representing callee *TagSet* implicitly tagged + with passed tag(s). With implicit tagging mode, new tag(s) replace the + last existing tag. + + Parameters + ---------- + superTag: :class:`~pyasn1.type.tag.Tag` + *Tag* object to tag this *TagSet* + + Returns + ------- + : :class:`~pyasn1.type.tag.TagSet` + New *TagSet* object + """ if self.__superTags: - superTag = Tag(tagClass, self.__superTags[-1][1], tagId) + superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId) return self[:-1] + superTag - def getBaseTag(self): return self.__baseTag - def __getitem__(self, idx): - if isinstance(idx, slice): - return self.__class__( - self.__baseTag, *getitem(self.__superTags, idx) - ) - return self.__superTags[idx] - def __eq__(self, other): return self.uniq == other.uniq - def __ne__(self, other): return self.uniq != other.uniq - def __lt__(self, other): return self.uniq < other.uniq - def __le__(self, other): return self.uniq <= other.uniq - def __gt__(self, other): return self.uniq > other.uniq - def __ge__(self, other): return self.uniq >= other.uniq - def __hash__(self): return self.__hashedSuperTags - def __len__(self): return self.__lenOfSuperTags def isSuperTagSetOf(self, tagSet): + """Test type relationship against given *TagSet* + + The callee is considered to be a supertype of given *TagSet* + tag-wise if all tags in *TagSet* are present in the callee and + they are in the same order. + + Parameters + ---------- + tagSet: :class:`~pyasn1.type.tag.TagSet` + *TagSet* object to evaluate against the callee + + Returns + ------- + : :py:class:`bool` + `True` if callee is a supertype of *tagSet* + """ if len(tagSet) < self.__lenOfSuperTags: - return - idx = self.__lenOfSuperTags - 1 - while idx >= 0: - if self.__superTags[idx] != tagSet[idx]: - return - idx = idx - 1 - return 1 - -def initTagSet(tag): return TagSet(tag, tag) + return False + return self.__superTags == tagSet[:self.__lenOfSuperTags] + + # Backward compatibility + + def getBaseTag(self): + return self.__baseTag + +def initTagSet(tag): + return TagSet(tag, tag) diff --git a/third_party/python/pyasn1/pyasn1/type/tagmap.py b/third_party/python/pyasn1/pyasn1/type/tagmap.py index 7cec3a10e4d8..32b74473c594 100644 --- a/third_party/python/pyasn1/pyasn1/type/tagmap.py +++ b/third_party/python/pyasn1/pyasn1/type/tagmap.py @@ -1,52 +1,102 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# from pyasn1 import error -class TagMap: - def __init__(self, posMap={}, negMap={}, defType=None): - self.__posMap = posMap.copy() - self.__negMap = negMap.copy() - self.__defType = defType - +__all__ = ['TagMap'] + + +class TagMap(object): + """Map *TagSet* objects to ASN.1 types + + Create an object mapping *TagSet* object to ASN.1 type. + + *TagMap* objects are immutable and duck-type read-only Python + :class:`dict` objects holding *TagSet* objects as keys and ASN.1 + type objects as values. + + Parameters + ---------- + presentTypes: :py:class:`dict` + Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered + as being unconditionally present in the *TagMap*. + + skipTypes: :py:class:`dict` + A collection of :class:`~pyasn1.type.tag.TagSet` objects considered + as absent in the *TagMap* even when *defaultType* is present. + + defaultType: ASN.1 type object + An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present + in *presentTypes* (unless given key is present in *skipTypes*). + """ + def __init__(self, presentTypes=None, skipTypes=None, defaultType=None): + self.__presentTypes = presentTypes or {} + self.__skipTypes = skipTypes or {} + self.__defaultType = defaultType + def __contains__(self, tagSet): - return tagSet in self.__posMap or \ - self.__defType is not None and tagSet not in self.__negMap + return (tagSet in self.__presentTypes or + self.__defaultType is not None and tagSet not in self.__skipTypes) def __getitem__(self, tagSet): - if tagSet in self.__posMap: - return self.__posMap[tagSet] - elif tagSet in self.__negMap: - raise error.PyAsn1Error('Key in negative map') - elif self.__defType is not None: - return self.__defType - else: - raise KeyError() + try: + return self.__presentTypes[tagSet] + except KeyError: + if self.__defaultType is None: + raise KeyError() + elif tagSet in self.__skipTypes: + raise error.PyAsn1Error('Key in negative map') + else: + return self.__defaultType + + def __iter__(self): + return iter(self.__presentTypes) def __repr__(self): - s = '%r/%r' % (self.__posMap, self.__negMap) - if self.__defType is not None: - s = s + '/%r' % (self.__defType,) + s = self.__class__.__name__ + '(' + if self.__presentTypes: + s += 'presentTypes=%r, ' % (self.__presentTypes,) + if self.__skipTypes: + s += 'skipTypes=%r, ' % (self.__skipTypes,) + if self.__defaultType is not None: + s += 'defaultType=%r' % (self.__defaultType,) + return s + ')' + + def __str__(self): + s = self.__class__.__name__ + ': ' + if self.__presentTypes: + s += 'presentTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__presentTypes.values()]) + if self.__skipTypes: + s += 'skipTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__skipTypes.values()]) + if self.__defaultType is not None: + s += 'defaultType: %s, ' % self.__defaultType.prettyPrintType() return s - def clone(self, parentType, tagMap, uniq=False): - if self.__defType is not None and tagMap.getDef() is not None: - raise error.PyAsn1Error('Duplicate default value at %s' % (self,)) - if tagMap.getDef() is not None: - defType = tagMap.getDef() - else: - defType = self.__defType - - posMap = self.__posMap.copy() - for k in tagMap.getPosMap(): - if uniq and k in posMap: - raise error.PyAsn1Error('Duplicate positive key %s' % (k,)) - posMap[k] = parentType + @property + def presentTypes(self): + """Return *TagSet* to ASN.1 type map present in callee *TagMap*""" + return self.__presentTypes - negMap = self.__negMap.copy() - negMap.update(tagMap.getNegMap()) - - return self.__class__( - posMap, negMap, defType, - ) + @property + def skipTypes(self): + """Return *TagSet* collection unconditionally absent in callee *TagMap*""" + return self.__skipTypes - def getPosMap(self): return self.__posMap.copy() - def getNegMap(self): return self.__negMap.copy() - def getDef(self): return self.__defType + @property + def defaultType(self): + """Return default ASN.1 type being returned for any missing *TagSet*""" + return self.__defaultType + + # Backward compatibility + + def getPosMap(self): + return self.presentTypes + + def getNegMap(self): + return self.skipTypes + + def getDef(self): + return self.defaultType diff --git a/third_party/python/pyasn1/pyasn1/type/univ.py b/third_party/python/pyasn1/pyasn1/type/univ.py index 9cd16f8a2a97..a90c6483f2b1 100644 --- a/third_party/python/pyasn1/pyasn1/type/univ.py +++ b/third_party/python/pyasn1/pyasn1/type/univ.py @@ -1,509 +1,1364 @@ -# ASN.1 "universal" data types -import operator, sys +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys +import math from pyasn1.type import base, tag, constraint, namedtype, namedval, tagmap from pyasn1.codec.ber import eoo -from pyasn1.compat import octets +from pyasn1.compat import octets, integer, binary from pyasn1 import error +NoValue = base.NoValue +noValue = NoValue() + +__all__ = ['Integer', 'Boolean', 'BitString', 'OctetString', 'Null', + 'ObjectIdentifier', 'Real', 'Enumerated', 'SequenceOfAndSetOfBase', 'SequenceOf', + 'SetOf', 'SequenceAndSetBase', 'Sequence', 'Set', 'Choice', 'Any', + 'NoValue', 'noValue'] + # "Simple" ASN.1 types (yet incomplete) + class Integer(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( + """Create |ASN.1| type or object. + + |ASN.1| objects are immutable and duck-type Python :class:`int` objects. + + Parameters + ---------- + value : :class:`int`, :class:`str` or |ASN.1| object + Python integer or string literal or |ASN.1| class instance. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) - ) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers namedValues = namedval.NamedValues() - def __init__(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if namedValues is None: - self.__namedValues = self.namedValues + + # Optimization for faster codec lookup + typeId = base.AbstractSimpleAsn1Item.getTypeId() + + def __init__(self, value=noValue, **kwargs): + if 'namedValues' not in kwargs: + kwargs['namedValues'] = self.namedValues + + base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs) + + def __repr__(self): + if self.namedValues is not self.__class__.namedValues: + return '%s, %r)' % (base.AbstractSimpleAsn1Item.__repr__(self)[:-1], self.namedValues) else: - self.__namedValues = namedValues - base.AbstractSimpleAsn1Item.__init__( - self, value, tagSet, subtypeSpec - ) + return base.AbstractSimpleAsn1Item.__repr__(self) - def __and__(self, value): return self.clone(self._value & value) - def __rand__(self, value): return self.clone(value & self._value) - def __or__(self, value): return self.clone(self._value | value) - def __ror__(self, value): return self.clone(value | self._value) - def __xor__(self, value): return self.clone(self._value ^ value) - def __rxor__(self, value): return self.clone(value ^ self._value) - def __lshift__(self, value): return self.clone(self._value << value) - def __rshift__(self, value): return self.clone(self._value >> value) + def __and__(self, value): + return self.clone(self._value & value) - def __add__(self, value): return self.clone(self._value + value) - def __radd__(self, value): return self.clone(value + self._value) - def __sub__(self, value): return self.clone(self._value - value) - def __rsub__(self, value): return self.clone(value - self._value) - def __mul__(self, value): return self.clone(self._value * value) - def __rmul__(self, value): return self.clone(value * self._value) - def __mod__(self, value): return self.clone(self._value % value) - def __rmod__(self, value): return self.clone(value % self._value) - def __pow__(self, value, modulo=None): return self.clone(pow(self._value, value, modulo)) - def __rpow__(self, value): return self.clone(pow(value, self._value)) + def __rand__(self, value): + return self.clone(value & self._value) + + def __or__(self, value): + return self.clone(self._value | value) + + def __ror__(self, value): + return self.clone(value | self._value) + + def __xor__(self, value): + return self.clone(self._value ^ value) + + def __rxor__(self, value): + return self.clone(value ^ self._value) + + def __lshift__(self, value): + return self.clone(self._value << value) + + def __rshift__(self, value): + return self.clone(self._value >> value) + + def __add__(self, value): + return self.clone(self._value + value) + + def __radd__(self, value): + return self.clone(value + self._value) + + def __sub__(self, value): + return self.clone(self._value - value) + + def __rsub__(self, value): + return self.clone(value - self._value) + + def __mul__(self, value): + return self.clone(self._value * value) + + def __rmul__(self, value): + return self.clone(value * self._value) + + def __mod__(self, value): + return self.clone(self._value % value) + + def __rmod__(self, value): + return self.clone(value % self._value) + + def __pow__(self, value, modulo=None): + return self.clone(pow(self._value, value, modulo)) + + def __rpow__(self, value): + return self.clone(pow(value, self._value)) + + def __floordiv__(self, value): + return self.clone(self._value // value) + + def __rfloordiv__(self, value): + return self.clone(value // self._value) if sys.version_info[0] <= 2: - def __div__(self, value): return self.clone(self._value // value) - def __rdiv__(self, value): return self.clone(value // self._value) + def __div__(self, value): + if isinstance(value, float): + return Real(self._value / value) + else: + return self.clone(self._value / value) + + def __rdiv__(self, value): + if isinstance(value, float): + return Real(value / self._value) + else: + return self.clone(value / self._value) else: - def __truediv__(self, value): return self.clone(self._value / value) - def __rtruediv__(self, value): return self.clone(value / self._value) - def __divmod__(self, value): return self.clone(self._value // value) - def __rdivmod__(self, value): return self.clone(value // self._value) + def __truediv__(self, value): + return Real(self._value / value) + + def __rtruediv__(self, value): + return Real(value / self._value) + + def __divmod__(self, value): + return self.clone(divmod(self._value, value)) + + def __rdivmod__(self, value): + return self.clone(divmod(value, self._value)) __hash__ = base.AbstractSimpleAsn1Item.__hash__ - def __int__(self): return int(self._value) - if sys.version_info[0] <= 2: - def __long__(self): return long(self._value) - def __float__(self): return float(self._value) - def __abs__(self): return abs(self._value) - def __index__(self): return int(self._value) + def __int__(self): + return int(self._value) - def __lt__(self, value): return self._value < value - def __le__(self, value): return self._value <= value - def __eq__(self, value): return self._value == value - def __ne__(self, value): return self._value != value - def __gt__(self, value): return self._value > value - def __ge__(self, value): return self._value >= value + if sys.version_info[0] <= 2: + def __long__(self): + return long(self._value) + + def __float__(self): + return float(self._value) + + def __abs__(self): + return self.clone(abs(self._value)) + + def __index__(self): + return int(self._value) + + def __pos__(self): + return self.clone(+self._value) + + def __neg__(self): + return self.clone(-self._value) + + def __invert__(self): + return self.clone(~self._value) + + def __round__(self, n=0): + r = round(self._value, n) + if n: + return self.clone(r) + else: + return r + + def __floor__(self): + return math.floor(self._value) + + def __ceil__(self): + return math.ceil(self._value) + + if sys.version_info[0:2] > (2, 5): + def __trunc__(self): + return self.clone(math.trunc(self._value)) + + def __lt__(self, value): + return self._value < value + + def __le__(self, value): + return self._value <= value + + def __eq__(self, value): + return self._value == value + + def __ne__(self, value): + return self._value != value + + def __gt__(self, value): + return self._value > value + + def __ge__(self, value): + return self._value >= value def prettyIn(self, value): - if not isinstance(value, str): - try: - return int(value) - except: - raise error.PyAsn1Error( - 'Can\'t coerce %s into integer: %s' % (value, sys.exc_info()[1]) - ) - r = self.__namedValues.getValue(value) - if r is not None: - return r try: return int(value) - except: - raise error.PyAsn1Error( - 'Can\'t coerce %s into integer: %s' % (value, sys.exc_info()[1]) + + except ValueError: + try: + return self.namedValues[value] + + except KeyError: + raise error.PyAsn1Error( + 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) ) def prettyOut(self, value): - r = self.__namedValues.getName(value) - return r is None and str(value) or repr(r) + try: + return repr(self.namedValues[value]) - def getNamedValues(self): return self.__namedValues + except KeyError: + return str(value) - def clone(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if value is None and tagSet is None and subtypeSpec is None \ - and namedValues is None: - return self - if value is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) + def clone(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`int`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing symbolic aliases for numbers to use instead of inheriting from caller + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) + + def subtype(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`int`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the caller, then + use the result as new object's ASN.1 constraints. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Add given object representing symbolic aliases for numbers + to one of the caller, then use the result as new object's + named numbers. + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs) + + # backward compatibility + + def getNamedValues(self): + return self.namedValues - def subtype(self, value=None, implicitTag=None, explicitTag=None, - subtypeSpec=None, namedValues=None): - if value is None: - value = self._value - if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - else: - namedValues = namedValues + self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) class Boolean(Integer): - tagSet = baseTagSet = tag.initTagSet( + __doc__ = Integer.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01), - ) - subtypeSpec = Integer.subtypeSpec+constraint.SingleValueConstraint(0,1) - namedValues = Integer.namedValues.clone(('False', 0), ('True', 1)) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = Integer.subtypeSpec + constraint.SingleValueConstraint(0, 1) + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues(('False', 0), ('True', 1)) + + # Optimization for faster codec lookup + typeId = Integer.getTypeId() + class BitString(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( + """Create |ASN.1| type or object. + + |ASN.1| objects are immutable and duck-type both Python :class:`tuple` (as a tuple + of bits) and :class:`int` objects. + + Parameters + ---------- + value : :class:`int`, :class:`str` or |ASN.1| object + Python integer or string literal representing binary or hexadecimal + number or sequence of integer bits or |ASN.1| object. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) - ) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers namedValues = namedval.NamedValues() - def __init__(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if namedValues is None: - self.__namedValues = self.namedValues - else: - self.__namedValues = namedValues - base.AbstractSimpleAsn1Item.__init__( - self, value, tagSet, subtypeSpec - ) - def clone(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if value is None and tagSet is None and subtypeSpec is None \ - and namedValues is None: + # Optimization for faster codec lookup + typeId = base.AbstractSimpleAsn1Item.getTypeId() + + defaultBinValue = defaultHexValue = noValue + + if sys.version_info[0] < 3: + SizedIntegerBase = long + else: + SizedIntegerBase = int + + class SizedInteger(SizedIntegerBase): + bitLength = leadingZeroBits = None + + def setBitLength(self, bitLength): + self.bitLength = bitLength + self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0) return self - if value is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) - def subtype(self, value=None, implicitTag=None, explicitTag=None, - subtypeSpec=None, namedValues=None): - if value is None: - value = self._value - if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - else: - namedValues = namedValues + self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) + def __len__(self): + if self.bitLength is None: + self.setBitLength(integer.bitLength(self)) - def __str__(self): return str(tuple(self)) + return self.bitLength + + def __init__(self, value=noValue, **kwargs): + if value is noValue or value is None: + if kwargs: + try: + value = self.fromBinaryString(kwargs.pop('binValue')) + + except KeyError: + pass + + try: + value = self.fromHexString(kwargs.pop('hexValue')) + + except KeyError: + pass + + if value is noValue or value is None: + if self.defaultBinValue is not noValue: + value = self.fromBinaryString(self.defaultBinValue) + + elif self.defaultHexValue is not noValue: + value = self.fromHexString(self.defaultHexValue) + + if 'namedValues' not in kwargs: + kwargs['namedValues'] = self.namedValues + + base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs) + + def clone(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value : :class:`int`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Class instance representing BitString type enumerations + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) + + def subtype(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`int`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the caller, then + use the result as new object's ASN.1 constraints. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Add given object representing symbolic aliases for numbers + to one of the caller, then use the result as new object's + named numbers. + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs) + + def __str__(self): + return self.asBinary() + + def __eq__(self, other): + other = self.prettyIn(other) + return self is other or self._value == other and len(self._value) == len(other) + + def __ne__(self, other): + other = self.prettyIn(other) + return self._value != other or len(self._value) != len(other) + + def __lt__(self, other): + other = self.prettyIn(other) + return len(self._value) < len(other) or len(self._value) == len(other) and self._value < other + + def __le__(self, other): + other = self.prettyIn(other) + return len(self._value) <= len(other) or len(self._value) == len(other) and self._value <= other + + def __gt__(self, other): + other = self.prettyIn(other) + return len(self._value) > len(other) or len(self._value) == len(other) and self._value > other + + def __ge__(self, other): + other = self.prettyIn(other) + return len(self._value) >= len(other) or len(self._value) == len(other) and self._value >= other # Immutable sequence object protocol def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len - def __getitem__(self, i): - if isinstance(i, slice): - return self.clone(operator.getitem(self._value, i)) - else: - return self._value[i] + return len(self._value) - def __add__(self, value): return self.clone(self._value + value) - def __radd__(self, value): return self.clone(value + self._value) - def __mul__(self, value): return self.clone(self._value * value) - def __rmul__(self, value): return self * value + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone([self[x] for x in range(*i.indices(len(self)))]) + else: + length = len(self._value) - 1 + if i > length or i < 0: + raise IndexError('bit index out of range') + return (self._value >> (length - i)) & 1 + + def __iter__(self): + length = len(self._value) + while length: + length -= 1 + yield (self._value >> length) & 1 + + def __reversed__(self): + return reversed(tuple(self)) + + # arithmetic operators + + def __add__(self, value): + value = self.prettyIn(value) + return self.clone(self.SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value))) + + def __radd__(self, value): + value = self.prettyIn(value) + return self.clone(self.SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value))) + + def __mul__(self, value): + bitString = self._value + while value > 1: + bitString <<= len(self._value) + bitString |= self._value + value -= 1 + return self.clone(bitString) + + def __rmul__(self, value): + return self * value + + def __lshift__(self, count): + return self.clone(self.SizedInteger(self._value << count).setBitLength(len(self._value) + count)) + + def __rshift__(self, count): + return self.clone(self.SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count))) + + def __int__(self): + return self._value + + def __float__(self): + return float(self._value) + + if sys.version_info[0] < 3: + def __long__(self): + return self._value + + def asNumbers(self): + """Get |ASN.1| value as a sequence of 8-bit integers. + + If |ASN.1| object length is not a multiple of 8, result + will be left-padded with zeros. + """ + return tuple(octets.octs2ints(self.asOctets())) + + def asOctets(self): + """Get |ASN.1| value as a sequence of octets. + + If |ASN.1| object length is not a multiple of 8, result + will be left-padded with zeros. + """ + return integer.to_bytes(self._value, length=len(self)) + + def asInteger(self): + """Get |ASN.1| value as a single integer value. + """ + return self._value + + def asBinary(self): + """Get |ASN.1| value as a text string of bits. + """ + binString = binary.bin(self._value)[2:] + return '0' * (len(self._value) - len(binString)) + binString + + @classmethod + def fromHexString(cls, value): + """Create a |ASN.1| object initialized from the hex string. + + Parameters + ---------- + value: :class:`str` + Text string like 'DEADBEEF' + """ + try: + return cls.SizedInteger(value, 16).setBitLength(len(value) * 4) + + except ValueError: + raise error.PyAsn1Error('%s.fromHexString() error: %s' % (cls.__name__, sys.exc_info()[1])) + + @classmethod + def fromBinaryString(cls, value): + """Create a |ASN.1| object initialized from a string of '0' and '1'. + + Parameters + ---------- + value: :class:`str` + Text string like '1010111' + """ + try: + return cls.SizedInteger(value or '0', 2).setBitLength(len(value)) + + except ValueError: + raise error.PyAsn1Error('%s.fromBinaryString() error: %s' % (cls.__name__, sys.exc_info()[1])) + + @classmethod + def fromOctetString(cls, value, padding=0): + """Create a |ASN.1| object initialized from a string. + + Parameters + ---------- + value: :class:`str` (Py2) or :class:`bytes` (Py3) + Text string like '\\\\x01\\\\xff' (Py2) or b'\\\\x01\\\\xff' (Py3) + """ + return cls(cls.SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding)) def prettyIn(self, value): - r = [] - if not value: - return () - elif isinstance(value, str): - if value[0] == '\'': + if octets.isStringType(value): + if not value: + return self.SizedInteger(0).setBitLength(0) + + elif value[0] == '\'': # "'1011'B" -- ASN.1 schema representation (deprecated) if value[-2:] == '\'B': - for v in value[1:-2]: - if v == '0': - r.append(0) - elif v == '1': - r.append(1) - else: - raise error.PyAsn1Error( - 'Non-binary BIT STRING initializer %s' % (v,) - ) - return tuple(r) + return self.fromBinaryString(value[1:-2]) elif value[-2:] == '\'H': - for v in value[1:-2]: - i = 4 - v = int(v, 16) - while i: - i = i - 1 - r.append((v>>i)&0x01) - return tuple(r) + return self.fromHexString(value[1:-2]) else: raise error.PyAsn1Error( 'Bad BIT STRING value notation %s' % (value,) - ) - else: - for i in value.split(','): - j = self.__namedValues.getValue(i) - if j is None: - raise error.PyAsn1Error( - 'Unknown bit identifier \'%s\'' % (i,) - ) - if j >= len(r): - r.extend([0]*(j-len(r)+1)) - r[j] = 1 - return tuple(r) + ) + + elif self.namedValues and not value.isdigit(): # named bits like 'Urgent, Active' + names = [x.strip() for x in value.split(',')] + + try: + + bitPositions = [self.namedValues[name] for name in names] + + except KeyError: + raise error.PyAsn1Error('unknown bit name(s) in %r' % (names,)) + + rightmostPosition = max(bitPositions) + + number = 0 + for bitPosition in bitPositions: + number |= 1 << (rightmostPosition - bitPosition) + + return self.SizedInteger(number).setBitLength(rightmostPosition + 1) + + elif value.startswith('0x'): + return self.fromHexString(value[2:]) + + elif value.startswith('0b'): + return self.fromBinaryString(value[2:]) + + else: # assume plain binary string like '1011' + return self.fromBinaryString(value) + elif isinstance(value, (tuple, list)): - r = tuple(value) - for b in r: - if b and b != 1: - raise error.PyAsn1Error( - 'Non-binary BitString initializer \'%s\'' % (r,) - ) - return r - elif isinstance(value, BitString): - return tuple(value) + return self.fromBinaryString(''.join([b and '1' or '0' for b in value])) + + elif isinstance(value, (self.SizedInteger, BitString)): + return self.SizedInteger(value).setBitLength(len(value)) + + elif isinstance(value, intTypes): + return self.SizedInteger(value) + else: raise error.PyAsn1Error( 'Bad BitString initializer type \'%s\'' % (value,) - ) + ) def prettyOut(self, value): - return '\"\'%s\'B\"' % ''.join([str(x) for x in value]) + return '\'%s\'' % str(self) + + +try: + # noinspection PyStatementEffect + all + +except NameError: # Python 2.4 + # noinspection PyShadowingBuiltins + def all(iterable): + for element in iterable: + if not element: + return False + return True + class OctetString(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) - ) - defaultBinValue = defaultHexValue = base.noValue - encoding = 'us-ascii' - def __init__(self, value=None, tagSet=None, subtypeSpec=None, - encoding=None, binValue=None, hexValue=None): - if encoding is None: - self._encoding = self.encoding - else: - self._encoding = encoding - if binValue is not None: - value = self.fromBinaryString(binValue) - if hexValue is not None: - value = self.fromHexString(hexValue) - if value is None or value is base.noValue: - value = self.defaultHexValue - if value is None or value is base.noValue: - value = self.defaultBinValue - self.__intValue = None - base.AbstractSimpleAsn1Item.__init__(self, value, tagSet, subtypeSpec) + """Create |ASN.1| type or 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. + + Parameters + ---------- + value : :class:`str`, :class:`bytes` or |ASN.1| object + string (Python 2) or bytes (Python 3), alternatively unicode object + (Python 2) or string (Python 3) representing character string to be + serialized into octets (note `encoding` parameter) or |ASN.1| object. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in text string context. + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.AbstractSimpleAsn1Item.getTypeId() + + defaultBinValue = defaultHexValue = noValue + encoding = 'iso-8859-1' + + def __init__(self, value=noValue, **kwargs): + if kwargs: + if value is noValue or value is None: + try: + value = self.fromBinaryString(kwargs.pop('binValue')) + + except KeyError: + pass + + try: + value = self.fromHexString(kwargs.pop('hexValue')) + + except KeyError: + pass + + if value is noValue or value is None: + if self.defaultBinValue is not noValue: + value = self.fromBinaryString(self.defaultBinValue) + + elif self.defaultHexValue is not noValue: + value = self.fromHexString(self.defaultHexValue) + + if 'encoding' not in kwargs: + kwargs['encoding'] = self.encoding + + base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs) + + def clone(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value : :class:`str`, :class:`bytes` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) + or :class:`str` (Python 3) the payload when |ASN.1| + object is used in string context. + + binValue: :py:class:`str` + Binary string initializer. Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer. Example: 'DEADBEEF'. + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) + + def subtype(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value : :class:`str`, :class:`bytes` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to |ASN.1| object tag set + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to |ASN.1| object tag set + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the caller, then + use the result as new object's ASN.1 constraints. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) + or :class:`str` (Python 3) the payload when *OctetString* + object is used in string context. + + binValue: :py:class:`str` + Binary string initializer. Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer. Example: 'DEADBEEF'. + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs) - def clone(self, value=None, tagSet=None, subtypeSpec=None, - encoding=None, binValue=None, hexValue=None): - if value is None and tagSet is None and subtypeSpec is None and \ - encoding is None and binValue is None and hexValue is None: - return self - if value is None and binValue is None and hexValue is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if encoding is None: - encoding = self._encoding - return self.__class__( - value, tagSet, subtypeSpec, encoding, binValue, hexValue - ) - if sys.version_info[0] <= 2: def prettyIn(self, value): if isinstance(value, str): return value + elif isinstance(value, unicode): + try: + return value.encode(self.encoding) + except (LookupError, UnicodeEncodeError): + raise error.PyAsn1Error( + "Can't encode string '%s' with codec %s" % (value, self.encoding) + ) elif isinstance(value, (tuple, list)): try: - return ''.join([ chr(x) for x in value ]) + return ''.join([chr(x) for x in value]) except ValueError: raise error.PyAsn1Error( - 'Bad OctetString initializer \'%s\'' % (value,) - ) + 'Bad %s initializer \'%s\'' % (self.__class__.__name__, value) + ) else: return str(value) + + def __str__(self): + return str(self._value) + + def __unicode__(self): + try: + return self._value.decode(self.encoding) + + except UnicodeDecodeError: + raise error.PyAsn1Error( + "Can't decode string '%s' with codec %s" % (self._value, self.encoding) + ) + + def asOctets(self): + return str(self._value) + + def asNumbers(self): + return tuple([ord(x) for x in self._value]) + else: def prettyIn(self, value): if isinstance(value, bytes): return value - elif isinstance(value, OctetString): - return value.asOctets() - elif isinstance(value, (tuple, list, map)): + elif isinstance(value, str): try: - return bytes(value) - except ValueError: - raise error.PyAsn1Error( - 'Bad OctetString initializer \'%s\'' % (value,) - ) - else: - try: - return str(value).encode(self._encoding) + return value.encode(self.encoding) except UnicodeEncodeError: raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - - - def fromBinaryString(self, value): - bitNo = 8; byte = 0; r = () - for v in value: - if bitNo: - bitNo = bitNo - 1 - else: - bitNo = 7 - r = r + (byte,) - byte = 0 - if v == '0': - v = 0 - elif v == '1': - v = 1 - else: - raise error.PyAsn1Error( - 'Non-binary OCTET STRING initializer %s' % (v,) + 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self.encoding) ) - byte = byte | (v << bitNo) - return octets.ints2octs(r + (byte,)) - - def fromHexString(self, value): - r = p = () - for v in value: - if p: - r = r + (int(p+v, 16),) - p = () + elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way + return value.asOctets() + elif isinstance(value, base.AbstractSimpleAsn1Item): # this mostly targets Integer objects + return self.prettyIn(str(value)) + elif isinstance(value, (tuple, list)): + return self.prettyIn(bytes(value)) else: - p = v - if p: - r = r + (int(p+'0', 16),) - return octets.ints2octs(r) + return bytes(value) + + def __str__(self): + try: + return self._value.decode(self.encoding) + + except UnicodeDecodeError: + raise error.PyAsn1Error( + 'Can\'t decode string \'%s\' with \'%s\' codec at \'%s\'' % (self._value, self.encoding, self.__class__.__name__) + ) + + def __bytes__(self): + return bytes(self._value) + + def asOctets(self): + return bytes(self._value) + + def asNumbers(self): + return tuple(self._value) def prettyOut(self, value): if sys.version_info[0] <= 2: - numbers = tuple([ ord(x) for x in value ]) + numbers = tuple((ord(x) for x in value)) else: numbers = tuple(value) - if [ x for x in numbers if x < 32 or x > 126 ]: - return '0x' + ''.join([ '%.2x' % x for x in numbers ]) + for x in numbers: + if x < 32 or x > 126: + return '0x' + ''.join(('%.2x' % x for x in numbers)) else: - return str(value) + try: + return value.decode(self.encoding) + + except UnicodeDecodeError: + raise error.PyAsn1Error( + "Can't decode string '%s' with '%s' codec at '%s'" % (value, self.encoding, self.__class__.__name__) + ) + + @staticmethod + def fromBinaryString(value): + """Create a |ASN.1| object initialized from a string of '0' and '1'. + + Parameters + ---------- + value: :class:`str` + Text string like '1010111' + """ + bitNo = 8 + byte = 0 + r = [] + for v in value: + if bitNo: + bitNo -= 1 + else: + bitNo = 7 + r.append(byte) + byte = 0 + if v in ('0', '1'): + v = int(v) + else: + raise error.PyAsn1Error( + 'Non-binary OCTET STRING initializer %s' % (v,) + ) + byte |= v << bitNo + + r.append(byte) + + return octets.ints2octs(r) + + @staticmethod + def fromHexString(value): + """Create a |ASN.1| object initialized from the hex string. + + Parameters + ---------- + value: :class:`str` + Text string like 'DEADBEEF' + """ + r = [] + p = [] + for v in value: + if p: + r.append(int(p + v, 16)) + p = None + else: + p = v + if p: + r.append(int(p + '0', 16)) + + return octets.ints2octs(r) def __repr__(self): - if self._value is base.noValue: - return self.__class__.__name__ + '()' - if [ x for x in self.asNumbers() if x < 32 or x > 126 ]: - return self.__class__.__name__ + '(hexValue=\'' + ''.join([ '%.2x' % x for x in self.asNumbers() ])+'\')' - else: - return self.__class__.__name__ + '(\'' + self.prettyOut(self._value) + '\')' - - if sys.version_info[0] <= 2: - def __str__(self): return str(self._value) - def __unicode__(self): - return self._value.decode(self._encoding, 'ignore') - def asOctets(self): return self._value - def asNumbers(self): - if self.__intValue is None: - self.__intValue = tuple([ ord(x) for x in self._value ]) - return self.__intValue - else: - def __str__(self): return self._value.decode(self._encoding, 'ignore') - def __bytes__(self): return self._value - def asOctets(self): return self._value - def asNumbers(self): - if self.__intValue is None: - self.__intValue = tuple(self._value) - return self.__intValue - + r = [] + doHex = False + if self._value is not self.defaultValue: + for x in self.asNumbers(): + if x < 32 or x > 126: + doHex = True + break + if not doHex: + r.append('%r' % (self._value,)) + if self.tagSet is not self.__class__.tagSet: + r.append('tagSet=%r' % (self.tagSet,)) + if self.subtypeSpec is not self.__class__.subtypeSpec: + r.append('subtypeSpec=%r' % (self.subtypeSpec,)) + if self.encoding is not self.__class__.encoding: + r.append('encoding=%r' % (self.encoding,)) + if doHex: + r.append('hexValue=%r' % ''.join(['%.2x' % x for x in self.asNumbers()])) + return '%s(%s)' % (self.__class__.__name__, ', '.join(r)) + # Immutable sequence object protocol - + def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len + return len(self._value) + def __getitem__(self, i): - if isinstance(i, slice): - return self.clone(operator.getitem(self._value, i)) + if i.__class__ is slice: + return self.clone(self._value[i]) else: return self._value[i] - def __add__(self, value): return self.clone(self._value + self.prettyIn(value)) - def __radd__(self, value): return self.clone(self.prettyIn(value) + self._value) - def __mul__(self, value): return self.clone(self._value * value) - def __rmul__(self, value): return self * value + def __iter__(self): + return iter(self._value) + + def __contains__(self, value): + return value in self._value + + def __add__(self, value): + return self.clone(self._value + self.prettyIn(value)) + + def __radd__(self, value): + return self.clone(self.prettyIn(value) + self._value) + + def __mul__(self, value): + return self.clone(self._value * value) + + def __rmul__(self, value): + return self * value + + def __int__(self): + return int(self._value) + + def __float__(self): + return float(self._value) + + def __reversed__(self): + return reversed(self._value) + class Null(OctetString): + """Create |ASN.1| type or object. + + |ASN.1| objects are immutable and duck-type Python :class:`str` objects (always empty). + + Parameters + ---------- + value : :class:`str` or :py:class:`~pyasn1.type.univ.Null` object + Python empty string literal or *Null* class instance. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + """ defaultValue = ''.encode() # This is tightly constrained - tagSet = baseTagSet = tag.initTagSet( + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) - ) - subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint(''.encode()) - + ) + subtypeSpec = OctetString.subtypeSpec + constraint.SingleValueConstraint(octets.str2octs('')) + + # Optimization for faster codec lookup + typeId = OctetString.getTypeId() + + def clone(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller + + Returns + ------- + : :py:class:`~pyasn1.type.univ.Null` + new instance of NULL type/value + """ + return OctetString.clone(self, value, **kwargs) + + def subtype(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`int`, :class:`str` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + Returns + ------- + : :py:class:`~pyasn1.type.univ.Null` + new instance of NULL type/value + """ + return OctetString.subtype(self, value, **kwargs) + + if sys.version_info[0] <= 2: intTypes = (int, long) else: - intTypes = int + intTypes = (int,) + +numericTypes = intTypes + (float,) + class ObjectIdentifier(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) - ) - def __add__(self, other): return self.clone(self._value + other) - def __radd__(self, other): return self.clone(other + self._value) + """Create |ASN.1| type or object. + + |ASN.1| objects are immutable and duck-type Python :class:`tuple` objects (tuple of non-negative integers). + + Parameters + ---------- + value: :class:`tuple`, :class:`str` or |ASN.1| object + Python sequence of :class:`int` or string literal or |ASN.1| object. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.AbstractSimpleAsn1Item.getTypeId() + + def __add__(self, other): + return self.clone(self._value + other) + + def __radd__(self, other): + return self.clone(other + self._value) + + def asTuple(self): + return self._value - def asTuple(self): return self._value - # Sequence object protocol - + def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len + return len(self._value) + def __getitem__(self, i): - if isinstance(i, slice): - return self.clone( - operator.getitem(self._value, i) - ) + if i.__class__ is slice: + return self.clone(self._value[i]) else: return self._value[i] - def __str__(self): return self.prettyPrint() - - def index(self, suboid): return self._value.index(suboid) + def __iter__(self): + return iter(self._value) - def isPrefixOf(self, value): - """Returns true if argument OID resides deeper in the OID tree""" + def __contains__(self, value): + return value in self._value + + def __str__(self): + return self.prettyPrint() + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, self.prettyPrint()) + + def index(self, suboid): + return self._value.index(suboid) + + def isPrefixOf(self, other): + """Indicate if this |ASN.1| object is a prefix of other |ASN.1| object. + + Parameters + ---------- + other: |ASN.1| object + |ASN.1| object + + Returns + ------- + : :class:`bool` + :class:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object + or :class:`False` otherwise. + """ l = len(self) - if l <= len(value): - if self._value[:l] == value[:l]: - return 1 - return 0 + if l <= len(other): + if self._value[:l] == other[:l]: + return True + return False def prettyIn(self, value): - """Dotted -> tuple of numerics OID converter""" - if isinstance(value, tuple): - pass - elif isinstance(value, ObjectIdentifier): - return tuple(value) - elif isinstance(value, str): - r = [] - for element in [ x for x in value.split('.') if x != '' ]: - try: - r.append(int(element, 0)) - except ValueError: - raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % - (str(value), self.__class__.__name__, sys.exc_info()[1]) - ) - value = tuple(r) - else: + if isinstance(value, ObjectIdentifier): + return tuple(value) + elif octets.isStringType(value): + if '-' in value: + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) try: - value = tuple(value) - except TypeError: + return tuple([int(subOid) for subOid in value.split('.') if subOid]) + except ValueError: raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % - (str(value), self.__class__.__name__,sys.exc_info()[1]) - ) + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + + try: + tupleOfInts = tuple([int(subOid) for subOid in value if subOid >= 0]) + + except (ValueError, TypeError): + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + + if len(tupleOfInts) == len(value): + return tupleOfInts + + raise error.PyAsn1Error('Malformed Object ID %s at %s' % (value, self.__class__.__name__)) + + def prettyOut(self, value): + return '.'.join([str(x) for x in value]) - for x in value: - if not isinstance(x, intTypes) or x < 0: - raise error.PyAsn1Error( - 'Invalid sub-ID in %s at %s' % (value, self.__class__.__name__) - ) - - return value - def prettyOut(self, value): return '.'.join([ str(x) for x in value ]) - class Real(base.AbstractSimpleAsn1Item): + """Create |ASN.1| type or 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 + elements are mantissa, base and exponent. + + Parameters + ---------- + value: :class:`tuple`, :class:`float` or |ASN.1| object + Python sequence of :class:`int` (representing mantissa, base and + exponent) or float instance or *Real* class instance. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + Raises + ------ + : :py:class:`pyasn1.error.PyAsn1Error` + On constraint violation or bad initializer. + + """ + binEncBase = None # binEncBase = 16 is recommended for large numbers + try: _plusInf = float('inf') _minusInf = float('-inf') @@ -513,108 +1368,289 @@ class Real(base.AbstractSimpleAsn1Item): _plusInf = _minusInf = None _inf = () - tagSet = baseTagSet = tag.initTagSet( + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) - ) + ) - def __normalizeBase10(self, value): + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.AbstractSimpleAsn1Item.getTypeId() + + def clone(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *clone()* method will replace corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`tuple`, :class:`float` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs) + + def subtype(self, value=noValue, **kwargs): + """Create a copy of a |ASN.1| type or object. + + Any parameters to the *subtype()* method will be added to the corresponding + properties of the |ASN.1| object. + + Parameters + ---------- + value: :class:`tuple`, :class:`float` or |ASN.1| object + Initialization value to pass to new ASN.1 object instead of + inheriting one from the caller. + + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to caller's + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller + + Returns + ------- + : + new instance of |ASN.1| type/value + """ + return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs) + + @staticmethod + def __normalizeBase10(value): m, b, e = value while m and m % 10 == 0: - m = m / 10 - e = e + 1 + m /= 10 + e += 1 return m, b, e def prettyIn(self, value): if isinstance(value, tuple) and len(value) == 3: - for d in value: - if not isinstance(d, intTypes): - raise error.PyAsn1Error( - 'Lame Real value syntax: %s' % (value,) - ) + if not isinstance(value[0], numericTypes) or \ + not isinstance(value[1], intTypes) or \ + not isinstance(value[2], intTypes): + raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,)) + if isinstance(value[0], float) and \ + self._inf and value[0] in self._inf: + return value[0] if value[1] not in (2, 10): raise error.PyAsn1Error( 'Prohibited base for Real value: %s' % (value[1],) - ) + ) if value[1] == 10: value = self.__normalizeBase10(value) return value elif isinstance(value, intTypes): return self.__normalizeBase10((value, 10, 0)) - elif isinstance(value, float): + elif isinstance(value, float) or octets.isStringType(value): + if octets.isStringType(value): + try: + value = float(value) + except ValueError: + raise error.PyAsn1Error( + 'Bad real value syntax: %s' % (value,) + ) if self._inf and value in self._inf: return value else: e = 0 while int(value) != value: - value = value * 10 - e = e - 1 + value *= 10 + e -= 1 return self.__normalizeBase10((int(value), 10, e)) elif isinstance(value, Real): return tuple(value) - elif isinstance(value, str): # handle infinite literal - try: - return float(value) - except ValueError: - pass raise error.PyAsn1Error( 'Bad real value syntax: %s' % (value,) - ) - + ) + def prettyOut(self, value): if value in self._inf: return '\'%s\'' % value else: return str(value) - def isPlusInfinity(self): return self._value == self._plusInf - def isMinusInfinity(self): return self._value == self._minusInf - def isInfinity(self): return self._value in self._inf - - def __str__(self): return str(float(self)) - - def __add__(self, value): return self.clone(float(self) + value) - def __radd__(self, value): return self + value - def __mul__(self, value): return self.clone(float(self) * value) - def __rmul__(self, value): return self * value - def __sub__(self, value): return self.clone(float(self) - value) - def __rsub__(self, value): return self.clone(value - float(self)) - def __mod__(self, value): return self.clone(float(self) % value) - def __rmod__(self, value): return self.clone(value % float(self)) - def __pow__(self, value, modulo=None): return self.clone(pow(float(self), value, modulo)) - def __rpow__(self, value): return self.clone(pow(value, float(self))) + def prettyPrint(self, scope=0): + if self.isInf: + return self.prettyOut(self._value) + else: + try: + return str(float(self)) + + except OverflowError: + return '' + + @property + def isPlusInf(self): + """Indicate PLUS-INFINITY object value + + Returns + ------- + : :class:`bool` + :class:`True` if calling object represents plus infinity + or :class:`False` otherwise. + + """ + return self._value == self._plusInf + + @property + def isMinusInf(self): + """Indicate MINUS-INFINITY object value + + Returns + ------- + : :class:`bool` + :class:`True` if calling object represents minus infinity + or :class:`False` otherwise. + """ + return self._value == self._minusInf + + @property + def isInf(self): + return self._value in self._inf + + def __str__(self): + return str(float(self)) + + def __add__(self, value): + return self.clone(float(self) + value) + + def __radd__(self, value): + return self + value + + def __mul__(self, value): + return self.clone(float(self) * value) + + def __rmul__(self, value): + return self * value + + def __sub__(self, value): + return self.clone(float(self) - value) + + def __rsub__(self, value): + return self.clone(value - float(self)) + + def __mod__(self, value): + return self.clone(float(self) % value) + + def __rmod__(self, value): + return self.clone(value % float(self)) + + def __pow__(self, value, modulo=None): + return self.clone(pow(float(self), value, modulo)) + + def __rpow__(self, value): + return self.clone(pow(value, float(self))) if sys.version_info[0] <= 2: - def __div__(self, value): return self.clone(float(self) / value) - def __rdiv__(self, value): return self.clone(value / float(self)) + def __div__(self, value): + return self.clone(float(self) / value) + + def __rdiv__(self, value): + return self.clone(value / float(self)) else: - def __truediv__(self, value): return self.clone(float(self) / value) - def __rtruediv__(self, value): return self.clone(value / float(self)) - def __divmod__(self, value): return self.clone(float(self) // value) - def __rdivmod__(self, value): return self.clone(value // float(self)) + def __truediv__(self, value): + return self.clone(float(self) / value) + + def __rtruediv__(self, value): + return self.clone(value / float(self)) + + def __divmod__(self, value): + return self.clone(float(self) // value) + + def __rdivmod__(self, value): + return self.clone(value // float(self)) + + def __int__(self): + return int(float(self)) - def __int__(self): return int(float(self)) if sys.version_info[0] <= 2: - def __long__(self): return long(float(self)) + def __long__(self): + return long(float(self)) + def __float__(self): if self._value in self._inf: return self._value else: return float( self._value[0] * pow(self._value[1], self._value[2]) - ) - def __abs__(self): return abs(float(self)) + ) - def __lt__(self, value): return float(self) < value - def __le__(self, value): return float(self) <= value - def __eq__(self, value): return float(self) == value - def __ne__(self, value): return float(self) != value - def __gt__(self, value): return float(self) > value - def __ge__(self, value): return float(self) >= value + def __abs__(self): + return self.clone(abs(float(self))) + + def __pos__(self): + return self.clone(+float(self)) + + def __neg__(self): + return self.clone(-float(self)) + + def __round__(self, n=0): + r = round(float(self), n) + if n: + return self.clone(r) + else: + return r + + def __floor__(self): + return self.clone(math.floor(float(self))) + + def __ceil__(self): + return self.clone(math.ceil(float(self))) + + if sys.version_info[0:2] > (2, 5): + def __trunc__(self): + return self.clone(math.trunc(float(self))) + + def __lt__(self, value): + return float(self) < value + + def __le__(self, value): + return float(self) <= value + + def __eq__(self, value): + return float(self) == value + + def __ne__(self, value): + return float(self) != value + + def __gt__(self, value): + return float(self) > value + + def __ge__(self, value): + return float(self) >= value if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(float(self)) + def __nonzero__(self): + return bool(float(self)) else: - def __bool__(self): return bool(float(self)) + def __bool__(self): + return bool(float(self)) + __hash__ = base.AbstractSimpleAsn1Item.__hash__ def __getitem__(self, idx): @@ -622,390 +1658,1132 @@ class Real(base.AbstractSimpleAsn1Item): raise error.PyAsn1Error('Invalid infinite value operation') else: return self._value[idx] - + + # compatibility stubs + + def isPlusInfinity(self): + return self.isPlusInf + + def isMinusInfinity(self): + return self.isMinusInf + + def isInfinity(self): + return self.isInf + + class Enumerated(Integer): - tagSet = baseTagSet = tag.initTagSet( + __doc__ = Integer.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x0A) - ) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = Integer.getTypeId() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + # "Structured" ASN.1 types -class SetOf(base.AbstractConstructedAsn1Item): - componentType = None - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ) - typeId = 1 +class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item): + """Create |ASN.1| type. - def _cloneComponentValues(self, myClone, cloneValueFlag): - idx = 0; l = len(self._componentValues) - while idx < l: - c = self._componentValues[idx] - if c is not None: - if isinstance(c, base.AbstractConstructedAsn1Item): - myClone.setComponentByPosition( - idx, c.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByPosition(idx, c.clone()) - idx = idx + 1 - - def _verifyComponent(self, idx, value): - if self._componentType is not None and \ - not self._componentType.isSuperTypeOf(value): - raise error.PyAsn1Error('Component type error %s' % (value,)) + |ASN.1| objects are mutable and duck-type Python :class:`list` objects. - def getComponentByPosition(self, idx): return self._componentValues[idx] - def setComponentByPosition(self, idx, value=None, verifyConstraints=True): - l = len(self._componentValues) - if idx >= l: - self._componentValues = self._componentValues + (idx-l+1)*[None] - if value is None: - if self._componentValues[idx] is None: - if self._componentType is None: - raise error.PyAsn1Error('Component type not defined') - self._componentValues[idx] = self._componentType.clone() - self._componentValuesSet = self._componentValuesSet + 1 - return self - elif not isinstance(value, base.Asn1Item): - if self._componentType is None: - raise error.PyAsn1Error('Component type not defined') - if isinstance(self._componentType, base.AbstractSimpleAsn1Item): - value = self._componentType.clone(value=value) - else: - raise error.PyAsn1Error('Instance value required') - if verifyConstraints: - if self._componentType is not None: - self._verifyComponent(idx, value) - self._verifySubtypeSpec(value, idx) - if self._componentValues[idx] is None: - self._componentValuesSet = self._componentValuesSet + 1 - self._componentValues[idx] = value - return self + Parameters + ---------- + componentType : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A pyasn1 object representing ASN.1 type allowed within |ASN.1| type - def getComponentTagMap(self): - if self._componentType is not None: - return self._componentType.getTagMap() + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) - def prettyPrint(self, scope=0): - scope = scope + 1 - r = self.__class__.__name__ + ':\n' - for idx in range(len(self._componentValues)): - r = r + ' '*scope - if self._componentValues[idx] is None: - r = r + '' - else: - r = r + self._componentValues[idx].prettyPrint(scope) - return r + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) -class SequenceOf(SetOf): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ) - typeId = 2 + sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing collection size constraint + """ -class SequenceAndSetBase(base.AbstractConstructedAsn1Item): - componentType = namedtype.NamedTypes() - def __init__(self, componentType=None, tagSet=None, - subtypeSpec=None, sizeSpec=None): - base.AbstractConstructedAsn1Item.__init__( - self, componentType, tagSet, subtypeSpec, sizeSpec - ) - if self._componentType is None: - self._componentTypeLen = 0 - else: - self._componentTypeLen = len(self._componentType) + def __init__(self, *args, **kwargs): + # support positional params for backward compatibility + if args: + for key, value in zip(('componentType', 'tagSet', + 'subtypeSpec', 'sizeSpec'), args): + if key in kwargs: + raise error.PyAsn1Error('Conflicting positional and keyword params!') + kwargs['componentType'] = value + + base.AbstractConstructedAsn1Item.__init__(self, **kwargs) + + # Python list protocol def __getitem__(self, idx): - if isinstance(idx, str): - return self.getComponentByName(idx) - else: - return base.AbstractConstructedAsn1Item.__getitem__(self, idx) + try: + return self.getComponentByPosition(idx) + + except error.PyAsn1Error: + raise IndexError(sys.exc_info()[1]) def __setitem__(self, idx, value): - if isinstance(idx, str): - self.setComponentByName(idx, value) - else: - base.AbstractConstructedAsn1Item.__setitem__(self, idx, value) - + try: + self.setComponentByPosition(idx, value) + + except error.PyAsn1Error: + raise IndexError(sys.exc_info()[1]) + + def clear(self): + self._componentValues = [] + + def append(self, value): + self[len(self)] = value + + def count(self, value): + return self._componentValues.count(value) + + def extend(self, values): + for value in values: + self.append(value) + + def index(self, value, start=0, stop=None): + if stop is None: + stop = len(self) + try: + return self._componentValues.index(value, start, stop) + + except error.PyAsn1Error: + raise ValueError(sys.exc_info()[1]) + + def reverse(self): + self._componentValues.reverse() + + def sort(self, key=None, reverse=False): + self._componentValues.sort(key=key, reverse=reverse) + + def __iter__(self): + return iter(self._componentValues) + def _cloneComponentValues(self, myClone, cloneValueFlag): - idx = 0; l = len(self._componentValues) - while idx < l: - c = self._componentValues[idx] - if c is not None: - if isinstance(c, base.AbstractConstructedAsn1Item): + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue: + if isinstance(componentValue, base.AbstractConstructedAsn1Item): myClone.setComponentByPosition( - idx, c.clone(cloneValueFlag=cloneValueFlag) - ) + idx, componentValue.clone(cloneValueFlag=cloneValueFlag) + ) else: - myClone.setComponentByPosition(idx, c.clone()) - idx = idx + 1 - - def _verifyComponent(self, idx, value): - if idx >= self._componentTypeLen: - raise error.PyAsn1Error( - 'Component type error out of range' - ) - t = self._componentType[idx].getType() - if not t.isSuperTypeOf(value): - raise error.PyAsn1Error('Component type error %r vs %r' % (t, value)) - - def getComponentByName(self, name): - return self.getComponentByPosition( - self._componentType.getPositionByName(name) - ) - def setComponentByName(self, name, value=None, verifyConstraints=True): - return self.setComponentByPosition( - self._componentType.getPositionByName(name), value, - verifyConstraints - ) + myClone.setComponentByPosition(idx, componentValue.clone()) def getComponentByPosition(self, idx): + """Return |ASN.1| type component value by position. + + Equivalent to Python sequence subscription operation (e.g. `[]`). + + Parameters + ---------- + idx : :class:`int` + Component index (zero-based). Must either refer to an existing + component or to N+1 component (if *componentType* is set). In the latter + case a new component type gets instantiated and appended to the |ASN.1| + sequence. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a pyasn1 object + """ try: return self._componentValues[idx] except IndexError: - if idx < self._componentTypeLen: - return - raise - def setComponentByPosition(self, idx, value=None, verifyConstraints=True): - l = len(self._componentValues) - if idx >= l: - self._componentValues = self._componentValues + (idx-l+1)*[None] - if value is None: - if self._componentValues[idx] is None: - self._componentValues[idx] = self._componentType.getTypeByPosition(idx).clone() - self._componentValuesSet = self._componentValuesSet + 1 - return self + self.setComponentByPosition(idx) + return self._componentValues[idx] + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`) + or list.append() (when idx == len(self)). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to existing + component or to N+1 component. In the latter case a new component + type gets instantiated (if *componentType* is set, or given ASN.1 + object is taken otherwise) and appended to the |ASN.1| sequence. + + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + + verifyConstraints: :class:`bool` + If `False`, skip constraints validation + + matchTags: :class:`bool` + If `False`, skip component tags matching + + matchConstraints: :class:`bool` + If `False`, skip component constraints matching + + Returns + ------- + self + + Raises + ------ + IndexError: + When idx > len(self) + """ + if value is None: # backward compatibility + value = noValue + + componentType = self.componentType + + try: + currentValue = self._componentValues[idx] + except IndexError: + currentValue = noValue + + if len(self._componentValues) < idx: + raise error.PyAsn1Error('Component index out of range') + + if value is noValue: + if componentType is not None: + value = componentType.clone() + elif currentValue is noValue: + raise error.PyAsn1Error('Component type not defined') elif not isinstance(value, base.Asn1Item): - t = self._componentType.getTypeByPosition(idx) - if isinstance(t, base.AbstractSimpleAsn1Item): - value = t.clone(value=value) + if componentType is not None and isinstance(componentType, base.AbstractSimpleAsn1Item): + value = componentType.clone(value=value) + elif currentValue is not noValue and isinstance(currentValue, base.AbstractSimpleAsn1Item): + value = currentValue.clone(value=value) else: - raise error.PyAsn1Error('Instance value required') - if verifyConstraints: - if self._componentTypeLen: - self._verifyComponent(idx, value) - self._verifySubtypeSpec(value, idx) - if self._componentValues[idx] is None: - self._componentValuesSet = self._componentValuesSet + 1 - self._componentValues[idx] = value + raise error.PyAsn1Error('Non-ASN.1 value %r and undefined component type at %r' % (value, self)) + elif componentType is not None: + if self.strictConstraints: + if not componentType.isSameTypeWith(value, matchTags, matchConstraints): + raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) + else: + if not componentType.isSuperTypeOf(value, matchTags, matchConstraints): + raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) + + if verifyConstraints and value.isValue: + try: + self.subtypeSpec(value, idx) + + except error.PyAsn1Error: + exType, exValue, exTb = sys.exc_info() + raise exType('%s at %s' % (exValue, self.__class__.__name__)) + + if currentValue is noValue: + self._componentValues.append(value) + else: + self._componentValues[idx] = value + return self - def getNameByPosition(self, idx): - if self._componentTypeLen: - return self._componentType.getNameByPosition(idx) + @property + def componentTagMap(self): + if self.componentType is not None: + return self.componentType.tagMap - def getDefaultComponentByPosition(self, idx): - if self._componentTypeLen and self._componentType[idx].isDefaulted: - return self._componentType[idx].getType() + def prettyPrint(self, scope=0): + scope += 1 + representation = self.__class__.__name__ + ':\n' + for idx, componentValue in enumerate(self._componentValues): + representation += ' ' * scope + if (componentValue is noValue and + self.componentType is not None): + representation += '' + else: + representation += componentValue.prettyPrint(scope) + return representation + + def prettyPrintType(self, scope=0): + scope += 1 + representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) + if self.componentType is not None: + representation += ' ' * scope + representation += self.componentType.prettyPrintType(scope) + return representation + '\n' + ' ' * (scope - 1) + '}' + + + @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. + + For the purpose of this check, empty |ASN.1| object is considered + as initialized. + + Returns + ------- + : :class:`bool` + :class:`True` if object represents ASN.1 value and type, + :class:`False` if object represents just ASN.1 type. + + 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. + """ + for componentValue in self._componentValues: + if not componentValue.isValue: + return False + + return True + + +class SequenceOf(SequenceOfAndSetOfBase): + __doc__ = SequenceOfAndSetOfBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ) + + #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = None + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing size constraint on |ASN.1| objects + sizeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceOfAndSetOfBase.getTypeId() + + +class SetOf(SequenceOfAndSetOfBase): + __doc__ = SequenceOfAndSetOfBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ) + + #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = None + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing size constraint on |ASN.1| objects + sizeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceOfAndSetOfBase.getTypeId() + + +class SequenceAndSetBase(base.AbstractConstructedAsn1Item): + """Create |ASN.1| type. + + |ASN.1| objects are mutable and duck-type Python :class:`dict` objects. + + Parameters + ---------- + componentType: :py:class:`~pyasn1.type.namedtype.NamedType` + Object holding named ASN.1 types allowed within this collection + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s) + + sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing collection size constraint + """ + #: Default :py:class:`~pyasn1.type.namedtype.NamedTypes` + #: object representing named ASN.1 types allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + + class DynamicNames(object): + """Fields names/positions mapping for component-less objects""" + def __init__(self): + self._keyToIdxMap = {} + self._idxToKeyMap = {} + + def __len__(self): + return len(self._keyToIdxMap) + + def __contains__(self, item): + return item in self._keyToIdxMap or item in self._idxToKeyMap + + def __iter__(self): + return (self._idxToKeyMap[idx] for idx in range(len(self._idxToKeyMap))) + + def __getitem__(self, item): + try: + return self._keyToIdxMap[item] + + except KeyError: + return self._idxToKeyMap[item] + + def getNameByPosition(self, idx): + try: + return self._idxToKeyMap[idx] + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByName(self, name): + try: + return self._keyToIdxMap[name] + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + def addField(self, idx): + self._keyToIdxMap['field-%d' % idx] = idx + self._idxToKeyMap[idx] = 'field-%d' % idx + + + def __init__(self, **kwargs): + base.AbstractConstructedAsn1Item.__init__(self, **kwargs) + self._componentTypeLen = len(self.componentType) + self._dynamicNames = self._componentTypeLen or self.DynamicNames() + + def __getitem__(self, idx): + if octets.isStringType(idx): + try: + return self.getComponentByName(idx) + + except error.PyAsn1Error: + # duck-typing dict + raise KeyError(sys.exc_info()[1]) + + else: + try: + return self.getComponentByPosition(idx) + + except error.PyAsn1Error: + # duck-typing list + raise IndexError(sys.exc_info()[1]) + + def __setitem__(self, idx, value): + if octets.isStringType(idx): + try: + self.setComponentByName(idx, value) + + except error.PyAsn1Error: + # duck-typing dict + raise KeyError(sys.exc_info()[1]) + + else: + try: + self.setComponentByPosition(idx, value) + + except error.PyAsn1Error: + # duck-typing list + raise IndexError(sys.exc_info()[1]) + + def __contains__(self, key): + if self._componentTypeLen: + return key in self.componentType + else: + return key in self._dynamicNames + + def __iter__(self): + return iter(self.componentType or self._dynamicNames) + + # Python dict protocol + + def values(self): + for idx in range(self._componentTypeLen or len(self._dynamicNames)): + yield self[idx] + + def keys(self): + return iter(self) + + def items(self): + for idx in range(self._componentTypeLen or len(self._dynamicNames)): + if self._componentTypeLen: + yield self.componentType[idx].name, self[idx] + else: + yield self._dynamicNames[idx], self[idx] + + def update(self, *iterValue, **mappingValue): + for k, v in iterValue: + self[k] = v + for k in mappingValue: + self[k] = mappingValue[k] + + def clear(self): + self._componentValues = [] + self._dynamicNames = self.DynamicNames() + + def _cloneComponentValues(self, myClone, cloneValueFlag): + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue: + if isinstance(componentValue, base.AbstractConstructedAsn1Item): + myClone.setComponentByPosition( + idx, componentValue.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByPosition(idx, componentValue.clone()) + + def getComponentByName(self, name): + """Returns |ASN.1| type component by name. + + Equivalent to Python :class:`dict` subscription operation (e.g. `[]`). + + Parameters + ---------- + name : :class:`str` + |ASN.1| type component name + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + Instantiate |ASN.1| component type or return existing component value + """ + if self._componentTypeLen: + idx = self.componentType.getPositionByName(name) + else: + try: + idx = self._dynamicNames.getPositionByName(name) + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + return self.getComponentByPosition(idx) + + def setComponentByName(self, name, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by name. + + Equivalent to Python :class:`dict` item assignment operation (e.g. `[]`). + + Parameters + ---------- + name: :class:`str` + |ASN.1| type component name + + value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + + verifyConstraints: :class:`bool` + If `False`, skip constraints validation + + matchTags: :class:`bool` + If `False`, skip component tags matching + + matchConstraints: :class:`bool` + If `False`, skip component constraints matching + + Returns + ------- + self + """ + if self._componentTypeLen: + idx = self.componentType.getPositionByName(name) + else: + try: + idx = self._dynamicNames.getPositionByName(name) + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + + def getComponentByPosition(self, idx): + """Returns |ASN.1| type component by index. + + Equivalent to Python sequence subscription operation (e.g. `[]`). + + Parameters + ---------- + 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 + instantiated. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a PyASN1 object + """ + try: + componentValue = self._componentValues[idx] + except IndexError: + componentValue = noValue + + if componentValue is noValue: + self.setComponentByPosition(idx) + + return self._componentValues[idx] + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`). + + Parameters + ---------- + idx : :class:`int` + Component index (zero-based). Must either refer to existing + component (if *componentType* is set) or to N+1 component + otherwise. In the latter case a new component of given ASN.1 + type gets instantiated and appended to |ASN.1| sequence. + + value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + + verifyConstraints : :class:`bool` + If `False`, skip constraints validation + + matchTags: :class:`bool` + If `False`, skip component tags matching + + matchConstraints: :class:`bool` + If `False`, skip component constraints matching + + Returns + ------- + self + """ + if value is None: # backward compatibility + value = noValue + + componentType = self.componentType + componentTypeLen = self._componentTypeLen + + try: + currentValue = self._componentValues[idx] + except IndexError: + currentValue = noValue + if componentTypeLen: + if componentTypeLen < idx: + raise error.PyAsn1Error('component index out of range') + self._componentValues = [noValue] * componentTypeLen + + if value is noValue: + if componentTypeLen: + value = componentType.getTypeByPosition(idx).clone() + elif currentValue is noValue: + raise error.PyAsn1Error('Component type not defined') + elif not isinstance(value, base.Asn1Item): + if componentTypeLen: + subComponentType = componentType.getTypeByPosition(idx) + if isinstance(subComponentType, base.AbstractSimpleAsn1Item): + value = subComponentType.clone(value=value) + else: + raise error.PyAsn1Error('%s can cast only scalar values' % componentType.__class__.__name__) + elif currentValue is not noValue and isinstance(currentValue, base.AbstractSimpleAsn1Item): + value = currentValue.clone(value=value) + else: + raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__) + elif (matchTags or matchConstraints) and componentTypeLen: + subComponentType = componentType.getTypeByPosition(idx) + if subComponentType is not noValue: + if self.strictConstraints: + if not subComponentType.isSameTypeWith(value, matchTags, matchConstraints): + raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) + else: + if not subComponentType.isSuperTypeOf(value, matchTags, matchConstraints): + raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) + + if verifyConstraints and value.isValue: + try: + self.subtypeSpec(value, idx) + + except error.PyAsn1Error: + exType, exValue, exTb = sys.exc_info() + raise exType('%s at %s' % (exValue, self.__class__.__name__)) + + if componentTypeLen or idx in self._dynamicNames: + self._componentValues[idx] = value + elif len(self._componentValues) == idx: + self._componentValues.append(value) + self._dynamicNames.addField(idx) + else: + raise error.PyAsn1Error('Component index out of range') + + return self + + @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. + + For the purpose of check, the *OPTIONAL* and *DEFAULT* fields are + unconditionally considered as initialized. + + Returns + ------- + : :class:`bool` + :class:`True` if object represents ASN.1 value and type, + :class:`False` if object represents just ASN.1 type. + + 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. + """ + componentType = self.componentType + + if componentType: + for idx, subComponentType in enumerate(componentType.namedTypes): + if subComponentType.isDefaulted or subComponentType.isOptional: + continue + if (not self._componentValues or + not self._componentValues[idx].isValue): + return False + + else: + for componentValue in self._componentValues: + if not componentValue.isValue: + return False + + return True + + def prettyPrint(self, scope=0): + """Return an object representation string. + + Returns + ------- + : :class:`str` + Human-friendly object representation. + """ + scope += 1 + representation = self.__class__.__name__ + ':\n' + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue: + representation += ' ' * scope + if self.componentType: + representation += self.componentType.getNameByPosition(idx) + else: + representation += self._dynamicNames.getNameByPosition(idx) + representation = '%s=%s\n' % ( + representation, componentValue.prettyPrint(scope) + ) + return representation + + def prettyPrintType(self, scope=0): + scope += 1 + representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) + for idx, componentType in enumerate(self.componentType.values() or self._componentValues): + representation += ' ' * scope + if self.componentType: + representation += '"%s"' % self.componentType.getNameByPosition(idx) + else: + representation += '"%s"' % self._dynamicNames.getNameByPosition(idx) + representation = '%s = %s\n' % ( + representation, componentType.prettyPrintType(scope) + ) + return representation + '\n' + ' ' * (scope - 1) + '}' + + # backward compatibility + + def setDefaultComponents(self): + return self def getComponentType(self): if self._componentTypeLen: - return self._componentType - - def setDefaultComponents(self): - if self._componentTypeLen == self._componentValuesSet: - return - idx = self._componentTypeLen - while idx: - idx = idx - 1 - if self._componentType[idx].isDefaulted: - if self.getComponentByPosition(idx) is None: - self.setComponentByPosition(idx) - elif not self._componentType[idx].isOptional: - if self.getComponentByPosition(idx) is None: - raise error.PyAsn1Error( - 'Uninitialized component #%s at %r' % (idx, self) - ) + return self.componentType + + def getNameByPosition(self, idx): + if self._componentTypeLen: + return self.componentType[idx].name - def prettyPrint(self, scope=0): - scope = scope + 1 - r = self.__class__.__name__ + ':\n' - for idx in range(len(self._componentValues)): - if self._componentValues[idx] is not None: - r = r + ' '*scope - componentType = self.getComponentType() - if componentType is None: - r = r + '' - else: - r = r + componentType.getNameByPosition(idx) - r = '%s=%s\n' % ( - r, self._componentValues[idx].prettyPrint(scope) - ) - return r class Sequence(SequenceAndSetBase): - tagSet = baseTagSet = tag.initTagSet( + __doc__ = SequenceAndSetBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ) - typeId = 3 + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing constraints on |ASN.1| objects + sizeSpec = constraint.ConstraintsIntersection() + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object imposing size constraint on |ASN.1| objects + componentType = namedtype.NamedTypes() + + # Disambiguation ASN.1 types identification + typeId = SequenceAndSetBase.getTypeId() + + # backward compatibility def getComponentTagMapNearPosition(self, idx): - if self._componentType: - return self._componentType.getTagMapNearPosition(idx) - + if self.componentType: + return self.componentType.getTagMapNearPosition(idx) + def getComponentPositionNearType(self, tagSet, idx): - if self._componentType: - return self._componentType.getPositionNearType(tagSet, idx) + if self.componentType: + return self.componentType.getPositionNearType(tagSet, idx) else: return idx - -class Set(SequenceAndSetBase): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ) - typeId = 4 - def getComponent(self, innerFlag=0): return self - - def getComponentByType(self, tagSet, innerFlag=0): - c = self.getComponentByPosition( - self._componentType.getPositionByType(tagSet) - ) - if innerFlag and isinstance(c, Set): + +class Set(SequenceAndSetBase): + __doc__ = SequenceAndSetBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ) + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing constraints on |ASN.1| objects + sizeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceAndSetBase.getTypeId() + + def getComponent(self, innerFlag=False): + return self + + def getComponentByType(self, tagSet, innerFlag=False): + """Returns |ASN.1| type component by ASN.1 tag. + + Parameters + ---------- + tagSet : :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tags to identify one of + |ASN.1| object component + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a pyasn1 object + """ + component = self.getComponentByPosition( + self.componentType.getPositionByType(tagSet) + ) + if innerFlag and isinstance(component, Set): # get inner component by inner tagSet - return c.getComponent(1) + return component.getComponent(innerFlag=True) else: # get outer component by inner tagSet - return c - - def setComponentByType(self, tagSet, value=None, innerFlag=0, - verifyConstraints=True): - idx = self._componentType.getPositionByType(tagSet) - t = self._componentType.getTypeByPosition(idx) + return component + + def setComponentByType(self, tagSet, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True, + innerFlag=False): + """Assign |ASN.1| type component by ASN.1 tag. + + Parameters + ---------- + tagSet : :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tags to identify one of + |ASN.1| object component + + value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + + verifyConstraints : :class:`bool` + If `False`, skip constraints validation + + matchTags: :class:`bool` + If `False`, skip component tags matching + + matchConstraints: :class:`bool` + If `False`, skip component constraints matching + + innerFlag: :class:`bool` + If `True`, search for matching *tagSet* recursively. + + Returns + ------- + self + """ + idx = self.componentType.getPositionByType(tagSet) + if innerFlag: # set inner component by inner tagSet - if t.getTagSet(): + componentType = self.componentType.getTypeByPosition(idx) + + if componentType.tagSet: return self.setComponentByPosition( - idx, value, verifyConstraints - ) + idx, value, verifyConstraints, matchTags, matchConstraints + ) else: - t = self.setComponentByPosition(idx).getComponentByPosition(idx) - return t.setComponentByType( - tagSet, value, innerFlag, verifyConstraints - ) + componentType = self.getComponentByPosition(idx) + return componentType.setComponentByType( + tagSet, value, verifyConstraints, matchTags, matchConstraints, innerFlag=innerFlag + ) else: # set outer component by inner tagSet return self.setComponentByPosition( - idx, value, verifyConstraints - ) - - def getComponentTagMap(self): - if self._componentType: - return self._componentType.getTagMap(True) + idx, value, verifyConstraints, matchTags, matchConstraints + ) + + @property + def componentTagMap(self): + if self.componentType: + return self.componentType.tagMapUnique - def getComponentPositionByType(self, tagSet): - if self._componentType: - return self._componentType.getPositionByType(tagSet) class Choice(Set): - tagSet = baseTagSet = tag.TagSet() # untagged + __doc__ = Set.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.TagSet() # untagged + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing size constraint on |ASN.1| objects sizeSpec = constraint.ConstraintsIntersection( constraint.ValueSizeConstraint(1, 1) - ) - typeId = 5 + ) + + # Disambiguation ASN.1 types identification + typeId = Set.getTypeId() + _currentIdx = None def __eq__(self, other): if self._componentValues: return self._componentValues[self._currentIdx] == other return NotImplemented + def __ne__(self, other): if self._componentValues: return self._componentValues[self._currentIdx] != other return NotImplemented + def __lt__(self, other): if self._componentValues: return self._componentValues[self._currentIdx] < other return NotImplemented + def __le__(self, other): if self._componentValues: return self._componentValues[self._currentIdx] <= other return NotImplemented + def __gt__(self, other): if self._componentValues: return self._componentValues[self._currentIdx] > other return NotImplemented + def __ge__(self, other): if self._componentValues: return self._componentValues[self._currentIdx] >= other return NotImplemented - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._componentValues) - else: - def __bool__(self): return bool(self._componentValues) - def __len__(self): return self._currentIdx is not None and 1 or 0 - + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._componentValues and True or False + else: + def __bool__(self): + return self._componentValues and True or False + + def __len__(self): + return self._currentIdx is not None and 1 or 0 + + def __contains__(self, key): + if self._currentIdx is None: + return False + return key == self.componentType[self._currentIdx].getName() + + def __iter__(self): + if self._currentIdx is None: + raise StopIteration + yield self.componentType[self._currentIdx].getName() + + # Python dict protocol + + def values(self): + if self._currentIdx is not None: + yield self._componentValues[self._currentIdx] + + def keys(self): + if self._currentIdx is not None: + yield self.componentType[self._currentIdx].getName() + + def items(self): + if self._currentIdx is not None: + yield self.componentType[self._currentIdx].getName(), self[self._currentIdx] + def verifySizeSpec(self): if self._currentIdx is None: raise error.PyAsn1Error('Component not chosen') - else: - self._sizeSpec(' ') def _cloneComponentValues(self, myClone, cloneValueFlag): try: - c = self.getComponent() + component = self.getComponent() except error.PyAsn1Error: pass else: - if isinstance(c, Choice): - tagSet = c.getEffectiveTagSet() + if isinstance(component, Choice): + tagSet = component.effectiveTagSet else: - tagSet = c.getTagSet() - if isinstance(c, base.AbstractConstructedAsn1Item): + tagSet = component.tagSet + if isinstance(component, base.AbstractConstructedAsn1Item): myClone.setComponentByType( - tagSet, c.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByType(tagSet, c.clone()) - - def setComponentByPosition(self, idx, value=None, verifyConstraints=True): - l = len(self._componentValues) - if idx >= l: - self._componentValues = self._componentValues + (idx-l+1)*[None] - if self._currentIdx is not None: - self._componentValues[self._currentIdx] = None - if value is None: - if self._componentValues[idx] is None: - self._componentValues[idx] = self._componentType.getTypeByPosition(idx).clone() - self._componentValuesSet = 1 - self._currentIdx = idx - return self - elif not isinstance(value, base.Asn1Item): - value = self._componentType.getTypeByPosition(idx).clone( - value=value + tagSet, component.clone(cloneValueFlag=cloneValueFlag) ) - if verifyConstraints: - if self._componentTypeLen: - self._verifyComponent(idx, value) - self._verifySubtypeSpec(value, idx) - self._componentValues[idx] = value + else: + myClone.setComponentByType(tagSet, component.clone()) + + def getComponentByPosition(self, idx): + __doc__ = Set.__doc__ + + if self._currentIdx is None or self._currentIdx != idx: + return Set.getComponentByPosition(self, idx) + + return self._componentValues[idx] + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to existing + component or to N+1 component. In the latter case a new component + type gets instantiated (if *componentType* is set, or given ASN.1 + object is taken otherwise) and appended to the |ASN.1| sequence. + + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. Once a new value is + set to *idx* component, previous value is dropped. + + verifyConstraints : :class:`bool` + If `False`, skip constraints validation + + matchTags: :class:`bool` + If `False`, skip component tags matching + + matchConstraints: :class:`bool` + If `False`, skip component constraints matching + + Returns + ------- + self + """ + oldIdx = self._currentIdx + Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints) self._currentIdx = idx - self._componentValuesSet = 1 + if oldIdx is not None and oldIdx != idx: + self._componentValues[oldIdx] = None return self - def getMinTagSet(self): - if self._tagSet: - return self._tagSet + @property + def minTagSet(self): + if self.tagSet: + return self.tagSet else: - return self._componentType.genMinTagSet() + return self.componentType.minTagSet - def getEffectiveTagSet(self): - if self._tagSet: - return self._tagSet + @property + def effectiveTagSet(self): + """Return a :class:`~pyasn1.type.tag.TagSet` object of the currently initialized component or self (if |ASN.1| is tagged).""" + if self.tagSet: + return self.tagSet else: - c = self.getComponent() - if isinstance(c, Choice): - return c.getEffectiveTagSet() - else: - return c.getTagSet() + component = self.getComponent() + return component.effectiveTagSet - def getTagMap(self): - if self._tagSet: - return Set.getTagMap(self) + @property + def tagMap(self): + """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping + ASN.1 tags to ASN.1 objects contained within callee. + """ + if self.tagSet: + return Set.tagMap.fget(self) else: - return Set.getComponentTagMap(self) + return self.componentType.tagMapUnique def getComponent(self, innerFlag=0): + """Return currently assigned component of the |ASN.1| object. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a PyASN1 object + """ if self._currentIdx is None: raise error.PyAsn1Error('Component not chosen') else: @@ -1015,7 +2793,14 @@ class Choice(Set): else: return c - def getName(self, innerFlag=0): + def getName(self, innerFlag=False): + """Return the name of currently assigned component of the |ASN.1| object. + + Returns + ------- + : :py:class:`str` + |ASN.1| component name + """ if self._currentIdx is None: raise error.PyAsn1Error('Component not chosen') else: @@ -1023,20 +2808,68 @@ class Choice(Set): c = self._componentValues[self._currentIdx] if isinstance(c, Choice): return c.getName(innerFlag) - return self._componentType.getNameByPosition(self._currentIdx) + return self.componentType.getNameByPosition(self._currentIdx) + + @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. + + The PyASN1 value objects can additionally participate in most + of built-in Python operations. + + 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. + """ + if self._currentIdx is None: + return False + + return self._componentValues[self._currentIdx].isValue + + # compatibility stubs + + def getMinTagSet(self): + return self.minTagSet - def setDefaultComponents(self): pass class Any(OctetString): - tagSet = baseTagSet = tag.TagSet() # untagged - typeId = 6 + __doc__ = OctetString.__doc__ - def getTagMap(self): - return tagmap.TagMap( - { self.getTagSet(): self }, - { eoo.endOfOctets.getTagSet(): eoo.endOfOctets }, - self + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.TagSet() # untagged + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = OctetString.getTypeId() + + @property + def tagMap(self): + """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping + ASN.1 tags to ASN.1 objects contained within callee. + """ + try: + return self._tagMap + + except AttributeError: + self._tagMap = tagmap.TagMap( + {self.tagSet: self}, + {eoo.endOfOctets.tagSet: eoo.endOfOctets}, + self ) + return self._tagMap + # XXX # coercion rules? diff --git a/third_party/python/pyasn1/pyasn1/type/useful.py b/third_party/python/pyasn1/pyasn1/type/useful.py index a7139c22cef8..a05a9a6067f4 100644 --- a/third_party/python/pyasn1/pyasn1/type/useful.py +++ b/third_party/python/pyasn1/pyasn1/type/useful.py @@ -1,12 +1,187 @@ -# ASN.1 "useful" types -from pyasn1.type import char, tag +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import datetime +from pyasn1.type import univ, char, tag +from pyasn1.compat import string, dateandtime +from pyasn1 import error -class GeneralizedTime(char.VisibleString): +__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] + +NoValue = univ.NoValue +noValue = univ.noValue + + +class ObjectDescriptor(char.GraphicString): + __doc__ = char.GraphicString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.GraphicString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) + ) + + # Optimization for faster codec lookup + typeId = char.GraphicString.getTypeId() + + +class TimeMixIn(object): + + _yearsDigits = 4 + _hasSubsecond = False + _optionalMinutes = False + _shortTZ = False + + class FixedOffset(datetime.tzinfo): + """Fixed offset in minutes east from UTC.""" + + # defaulted arguments required + # https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html + def __init__(self, offset=0, name='UTC'): + self.__offset = datetime.timedelta(minutes=offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return datetime.timedelta(0) + + UTC = FixedOffset() + + @property + def asDateTime(self): + """Create :py:class:`datetime.datetime` object from a |ASN.1| object. + + Returns + ------- + : + new instance of :py:class:`datetime.datetime` object + """ + text = str(self) + if text.endswith('Z'): + tzinfo = TimeMixIn.UTC + text = text[:-1] + + elif '-' in text or '+' in text: + if '+' in text: + text, plusminus, tz = string.partition(text, '+') + else: + text, plusminus, tz = string.partition(text, '-') + + if self._shortTZ and len(tz) == 2: + tz += '00' + + if len(tz) != 4: + raise error.PyAsn1Error('malformed time zone offset %s' % tz) + + try: + minutes = int(tz[:2]) * 60 + int(tz[2:]) + if plusminus == '-': + minutes *= -1 + + except ValueError: + raise error.PyAsn1Error('unknown time specification %s' % self) + + tzinfo = TimeMixIn.FixedOffset(minutes, '?') + + else: + tzinfo = None + + if '.' in text or ',' in text: + if '.' in text: + text, _, ms = string.partition(text, '.') + else: + text, _, ms = string.partition(text, ',') + + try: + ms = int(ms) * 10000 + + except ValueError: + raise error.PyAsn1Error('bad sub-second time specification %s' % self) + + else: + ms = 0 + + if self._optionalMinutes and len(text) - self._yearsDigits == 6: + text += '0000' + elif len(text) - self._yearsDigits == 8: + text += '00' + + try: + dt = dateandtime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') + + except ValueError: + raise error.PyAsn1Error('malformed datetime format %s' % self) + + return dt.replace(microsecond=ms, tzinfo=tzinfo) + + @classmethod + def fromDateTime(cls, dt): + """Create |ASN.1| object from a :py:class:`datetime.datetime` object. + + Parameters + ---------- + dt : :py:class:`datetime.datetime` object + The `datetime.datetime` object to initialize the |ASN.1| object from + + + Returns + ------- + : + new instance of |ASN.1| value + """ + text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') + if cls._hasSubsecond: + text += '.%d' % (dt.microsecond // 10000) + + if dt.utcoffset(): + seconds = dt.utcoffset().seconds + if seconds < 0: + text += '-' + else: + text += '+' + text += '%.2d%.2d' % (seconds // 3600, seconds % 3600) + else: + text += 'Z' + + return cls(text) + + +class GeneralizedTime(char.VisibleString, TimeMixIn): + __doc__ = char.VisibleString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects tagSet = char.VisibleString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) - ) + ) -class UTCTime(char.VisibleString): + # Optimization for faster codec lookup + typeId = char.VideotexString.getTypeId() + + _yearsDigits = 4 + _hasSubsecond = True + _optionalMinutes = True + _shortTZ = True + + +class UTCTime(char.VisibleString, TimeMixIn): + __doc__ = char.VisibleString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects tagSet = char.VisibleString.tagSet.tagImplicitly( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) - ) + ) + + # Optimization for faster codec lookup + typeId = char.VideotexString.getTypeId() + + _yearsDigits = 2 + _hasSubsecond = False + _optionalMinutes = False + _shortTZ = False diff --git a/third_party/python/pyasn1/setup.cfg b/third_party/python/pyasn1/setup.cfg index 861a9f554263..6f08d0e3e7d4 100644 --- a/third_party/python/pyasn1/setup.cfg +++ b/third_party/python/pyasn1/setup.cfg @@ -1,3 +1,6 @@ +[bdist_wheel] +universal = 1 + [egg_info] tag_build = tag_date = 0 diff --git a/third_party/python/pyasn1/setup.py b/third_party/python/pyasn1/setup.py index 194f0c8ca8e7..a806c014eeb5 100644 --- a/third_party/python/pyasn1/setup.py +++ b/third_party/python/pyasn1/setup.py @@ -1,9 +1,10 @@ #!/usr/bin/env python -"""ASN.1 types and codecs - - A pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208). -""" - +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# import os import sys @@ -13,103 +14,107 @@ Environment :: Console Intended Audience :: Developers Intended Audience :: Education Intended Audience :: Information Technology -Intended Audience :: Science/Research Intended Audience :: System Administrators Intended Audience :: Telecommunications Industry License :: OSI Approved :: BSD License Natural Language :: English Operating System :: OS Independent Programming Language :: Python :: 2 +Programming Language :: Python :: 2.4 +Programming Language :: Python :: 2.5 +Programming Language :: Python :: 2.6 +Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 +Programming Language :: Python :: 3.2 +Programming Language :: Python :: 3.3 +Programming Language :: Python :: 3.4 +Programming Language :: Python :: 3.5 +Programming Language :: Python :: 3.6 Topic :: Communications -Topic :: Security :: Cryptography Topic :: Software Development :: Libraries :: Python Modules """ -def howto_install_distribute(): - print(""" - Error: You need the distribute Python package! - - It's very easy to install it, just type (as root on Linux): - - wget http://python-distribute.org/distribute_setup.py - python distribute_setup.py - - Then you could make eggs from this package. -""") def howto_install_setuptools(): print(""" Error: You need setuptools Python package! - It's very easy to install it, just type (as root on Linux): + It's very easy to install it, just type: - wget http://peak.telecommunity.com/dist/ez_setup.py + wget https://bootstrap.pypa.io/ez_setup.py python ez_setup.py Then you could make eggs from this package. """) + +if sys.version_info[:2] < (2, 4): + print("ERROR: this package requires Python 2.4 or later!") + sys.exit(1) + try: from setuptools import setup, Command + params = { 'zip_safe': True - } + } + except ImportError: for arg in sys.argv: - if arg.find('egg') != -1: - if sys.version_info[0] > 2: - howto_install_distribute() - else: - howto_install_setuptools() + if 'egg' in arg: + howto_install_setuptools() sys.exit(1) from distutils.core import setup, Command + params = {} -doclines = [ x.strip() for x in __doc__.split('\n') if x ] - -params.update( { +params.update({ 'name': 'pyasn1', - 'version': open(os.path.join('pyasn1','__init__.py')).read().split('\'')[1], - 'description': doclines[0], - 'long_description': ' '.join(doclines[1:]), - 'maintainer': 'Ilya Etingof ', + 'version': open(os.path.join('pyasn1', '__init__.py')).read().split('\'')[1], + 'description': 'ASN.1 types and codecs', + 'long_description': 'Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)', + 'maintainer': 'Ilya Etingof ', 'author': 'Ilya Etingof', - 'author_email': 'ilya@glas.net', - 'url': 'http://sourceforge.net/projects/pyasn1/', + 'author_email': 'etingof@gmail.com', + 'url': 'https://github.com/etingof/pyasn1', 'platforms': ['any'], - 'classifiers': [ x for x in classifiers.split('\n') if x ], + 'classifiers': [x for x in classifiers.split('\n') if x], 'license': 'BSD', - 'packages': [ 'pyasn1', - 'pyasn1.type', - 'pyasn1.compat', - 'pyasn1.codec', - 'pyasn1.codec.ber', - 'pyasn1.codec.cer', - 'pyasn1.codec.der' ] -} ) + 'packages': ['pyasn1', + 'pyasn1.type', + 'pyasn1.compat', + 'pyasn1.codec', + 'pyasn1.codec.ber', + 'pyasn1.codec.cer', + 'pyasn1.codec.der', + 'pyasn1.codec.native']}) # handle unittest discovery feature -if sys.version_info[0:2] < (2, 7) or \ - sys.version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - unittest = None -else: +try: + import unittest2 as unittest +except ImportError: import unittest -if unittest: - class PyTest(Command): - user_options = [] - def initialize_options(self): pass - def finalize_options(self): pass +class PyTest(Command): + user_options = [] - def run(self): - suite = unittest.defaultTestLoader.discover('.') - unittest.TextTestRunner(verbosity=2).run(suite) + def initialize_options(self): + pass - params['cmdclass'] = { 'test': PyTest } + def finalize_options(self): + pass + + def run(self): + suite = unittest.TestLoader().loadTestsFromNames( + ['tests.__main__.suite'] + ) + + unittest.TextTestRunner(verbosity=2).run(suite) + +params['cmdclass'] = { + 'test': PyTest, + 'tests': PyTest, +} setup(**params) diff --git a/third_party/python/pyasn1/test/codec/ber/suite.py b/third_party/python/pyasn1/test/codec/ber/suite.py deleted file mode 100644 index 796c526b4b7c..000000000000 --- a/third_party/python/pyasn1/test/codec/ber/suite.py +++ /dev/null @@ -1,22 +0,0 @@ -from sys import path, version_info -from os.path import sep -path.insert(1, path[0]+sep+'ber') -import test_encoder, test_decoder -from pyasn1.error import PyAsn1Error -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -suite = unittest.TestSuite() -loader = unittest.TestLoader() -for m in (test_encoder, test_decoder): - suite.addTest(loader.loadTestsFromModule(m)) - -def runTests(): unittest.TextTestRunner(verbosity=2).run(suite) - -if __name__ == '__main__': runTests() diff --git a/third_party/python/pyasn1/test/codec/ber/test_decoder.py b/third_party/python/pyasn1/test/codec/ber/test_decoder.py deleted file mode 100644 index 36999e84d4dc..000000000000 --- a/third_party/python/pyasn1/test/codec/ber/test_decoder.py +++ /dev/null @@ -1,535 +0,0 @@ -from pyasn1.type import tag, namedtype, univ -from pyasn1.codec.ber import decoder -from pyasn1.compat.octets import ints2octs, str2octs, null -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class LargeTagDecoderTestCase(unittest.TestCase): - def testLargeTag(self): - assert decoder.decode(ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))) == (1, null) - -class IntegerDecoderTestCase(unittest.TestCase): - def testPosInt(self): - assert decoder.decode(ints2octs((2, 1, 12))) == (12, null) - def testNegInt(self): - assert decoder.decode(ints2octs((2, 1, 244))) == (-12, null) - def testZero(self): - assert decoder.decode(ints2octs((2, 0))) == (0, null) - def testZeroLong(self): - assert decoder.decode(ints2octs((2, 1, 0))) == (0, null) - def testMinusOne(self): - assert decoder.decode(ints2octs((2, 1, 255))) == (-1, null) - def testPosLong(self): - assert decoder.decode( - ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255)) - ) == (0xffffffffffffffff, null) - def testNegLong(self): - assert decoder.decode( - ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1)) - ) == (-0xffffffffffffffff, null) - def testSpec(self): - try: - decoder.decode( - ints2octs((2, 1, 12)), asn1Spec=univ.Null() - ) == (12, null) - except PyAsn1Error: - pass - else: - assert 0, 'wrong asn1Spec worked out' - assert decoder.decode( - ints2octs((2, 1, 12)), asn1Spec=univ.Integer() - ) == (12, null) - def testTagFormat(self): - try: - decoder.decode(ints2octs((34, 1, 12))) - except PyAsn1Error: - pass - else: - assert 0, 'wrong tagFormat worked out' - -class BooleanDecoderTestCase(unittest.TestCase): - def testTrue(self): - assert decoder.decode(ints2octs((1, 1, 1))) == (1, null) - def testTrueNeg(self): - assert decoder.decode(ints2octs((1, 1, 255))) == (1, null) - def testExtraTrue(self): - assert decoder.decode(ints2octs((1, 1, 1, 0, 120, 50, 50))) == (1, ints2octs((0, 120, 50, 50))) - def testFalse(self): - assert decoder.decode(ints2octs((1, 1, 0))) == (0, null) - def testTagFormat(self): - try: - decoder.decode(ints2octs((33, 1, 1))) - except PyAsn1Error: - pass - else: - assert 0, 'wrong tagFormat worked out' - -class BitStringDecoderTestCase(unittest.TestCase): - def testDefMode(self): - assert decoder.decode( - ints2octs((3, 3, 1, 169, 138)) - ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null) - def testIndefMode(self): - assert decoder.decode( - ints2octs((3, 3, 1, 169, 138)) - ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null) - def testDefModeChunked(self): - assert decoder.decode( - ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)) - ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null) - def testIndefModeChunked(self): - assert decoder.decode( - ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)) - ) == ((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1), null) - def testDefModeChunkedSubst(self): - assert decoder.decode( - ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((3, 2, 0, 169, 3, 2, 1, 138)), 8) - def testIndefModeChunkedSubst(self): - assert decoder.decode( - ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((3, 2, 0, 169, 3, 2, 1, 138, 0, 0)), -1) - -class OctetStringDecoderTestCase(unittest.TestCase): - def testDefMode(self): - assert decoder.decode( - ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - ) == (str2octs('Quick brown fox'), null) - def testIndefMode(self): - assert decoder.decode( - ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0)) - ) == (str2octs('Quick brown fox'), null) - def testDefModeChunked(self): - assert decoder.decode( - ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)) - ) == (str2octs('Quick brown fox'), null) - def testIndefModeChunked(self): - assert decoder.decode( - ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)) - ) == (str2octs('Quick brown fox'), null) - def testDefModeChunkedSubst(self): - assert decoder.decode( - ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)), 23) - def testIndefModeChunkedSubst(self): - assert decoder.decode( - ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)), -1) - -class ExpTaggedOctetStringDecoderTestCase(unittest.TestCase): - def setUp(self): - self.o = univ.OctetString( - 'Quick brown fox', - tagSet=univ.OctetString.tagSet.tagExplicitly( - tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 5) - )) - - def testDefMode(self): - assert self.o.isSameTypeWith(decoder.decode( - ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - )[0]) - - def testIndefMode(self): - v, s = decoder.decode(ints2octs((101, 128, 36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0))) - assert self.o.isSameTypeWith(v) - assert not s - - def testDefModeChunked(self): - v, s = decoder.decode(ints2octs((101, 25, 36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120))) - assert self.o.isSameTypeWith(v) - assert not s - - def testIndefModeChunked(self): - v, s = decoder.decode(ints2octs((101, 128, 36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0, 0, 0))) - assert self.o.isSameTypeWith(v) - assert not s - - def testDefModeSubst(self): - assert decoder.decode( - ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), 17) - - def testIndefModeSubst(self): - assert decoder.decode( - ints2octs((101, 128, 36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)), -1) - -class NullDecoderTestCase(unittest.TestCase): - def testNull(self): - assert decoder.decode(ints2octs((5, 0))) == (null, null) - def testTagFormat(self): - try: - decoder.decode(ints2octs((37, 0))) - except PyAsn1Error: - pass - else: - assert 0, 'wrong tagFormat worked out' - -class ObjectIdentifierDecoderTestCase(unittest.TestCase): - def testOID(self): - assert decoder.decode( - ints2octs((6, 6, 43, 6, 0, 191, 255, 126)) - ) == ((1,3,6,0,0xffffe), null) - - def testEdges1(self): - assert decoder.decode( - ints2octs((6, 1, 255)) - ) == ((6,15), null) - - def testEdges2(self): - assert decoder.decode( - ints2octs((6, 1, 239)) - ) == ((5,39), null) - - def testEdges3(self): - assert decoder.decode( - ints2octs((6, 7, 43, 6, 143, 255, 255, 255, 127)) - ) == ((1, 3, 6, 4294967295), null) - - def testNonLeading0x80(self): - assert decoder.decode( - ints2octs((6, 5, 85, 4, 129, 128, 0)), - ) == ((2, 5, 4, 16384), null) - - def testLeading0x80(self): - try: - decoder.decode( - ints2octs((6, 5, 85, 4, 128, 129, 0)) - ) - except PyAsn1Error: - pass - else: - assert 1, 'Leading 0x80 tolarated' - - def testTagFormat(self): - try: - decoder.decode(ints2octs((38, 1, 239))) - except PyAsn1Error: - pass - else: - assert 0, 'wrong tagFormat worked out' - -class RealDecoderTestCase(unittest.TestCase): - def testChar(self): - assert decoder.decode( - ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49)) - ) == (univ.Real((123, 10, 11)), null) - - def testBin1(self): - assert decoder.decode( - ints2octs((9, 4, 128, 245, 4, 77)) - ) == (univ.Real((1101, 2, -11)), null) - - def testBin2(self): - assert decoder.decode( - ints2octs((9, 4, 128, 11, 4, 77)) - ) == (univ.Real((1101, 2, 11)), null) - - def testBin3(self): - assert decoder.decode( - ints2octs((9, 3, 192, 10, 123)) - ) == (univ.Real((-123, 2, 10)), null) - - - def testPlusInf(self): - assert decoder.decode( - ints2octs((9, 1, 64)) - ) == (univ.Real('inf'), null) - - def testMinusInf(self): - assert decoder.decode( - ints2octs((9, 1, 65)) - ) == (univ.Real('-inf'), null) - - def testEmpty(self): - assert decoder.decode( - ints2octs((9, 0)) - ) == (univ.Real(0.0), null) - - def testTagFormat(self): - try: - decoder.decode(ints2octs((41, 0))) - except PyAsn1Error: - pass - else: - assert 0, 'wrong tagFormat worked out' - -class SequenceDecoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Sequence(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null(null)), - namedtype.NamedType('first-name', univ.OctetString(null)), - namedtype.NamedType('age', univ.Integer(33)), - )) - self.s.setComponentByPosition(0, univ.Null(null)) - self.s.setComponentByPosition(1, univ.OctetString('quick brown')) - self.s.setComponentByPosition(2, univ.Integer(1)) - self.s.setDefaultComponents() - - def testWithOptionalAndDefaultedDefMode(self): - assert decoder.decode( - ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) - ) == (self.s, null) - - def testWithOptionalAndDefaultedIndefMode(self): - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) - ) == (self.s, null) - - def testWithOptionalAndDefaultedDefModeChunked(self): - assert decoder.decode( - ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) - ) == (self.s, null) - - def testWithOptionalAndDefaultedIndefModeChunked(self): - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) - ) == (self.s, null) - - def testWithOptionalAndDefaultedDefModeSubst(self): - assert decoder.decode( - ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), 18) - - def testWithOptionalAndDefaultedIndefModeSubst(self): - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), -1) - - def testTagFormat(self): - try: - decoder.decode( - ints2octs((16, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) - ) - except PyAsn1Error: - pass - else: - assert 0, 'wrong tagFormat worked out' - -class GuidedSequenceDecoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Sequence(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null(null)), - namedtype.OptionalNamedType('first-name', univ.OctetString(null)), - namedtype.DefaultedNamedType('age', univ.Integer(33)), - )) - - def __init(self): - self.s.clear() - self.s.setComponentByPosition(0, univ.Null(null)) - self.s.setDefaultComponents() - - def __initWithOptional(self): - self.s.clear() - self.s.setComponentByPosition(0, univ.Null(null)) - self.s.setComponentByPosition(1, univ.OctetString('quick brown')) - self.s.setDefaultComponents() - - def __initWithDefaulted(self): - self.s.clear() - self.s.setComponentByPosition(0, univ.Null(null)) - self.s.setComponentByPosition(2, univ.Integer(1)) - self.s.setDefaultComponents() - - def __initWithOptionalAndDefaulted(self): - self.s.clear() - self.s.setComponentByPosition(0, univ.Null(null)) - self.s.setComponentByPosition(1, univ.OctetString('quick brown')) - self.s.setComponentByPosition(2, univ.Integer(1)) - self.s.setDefaultComponents() - - def testDefMode(self): - self.__init() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testIndefMode(self): - self.__init() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testDefModeChunked(self): - self.__init() - assert decoder.decode( - ints2octs((48, 2, 5, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testIndefModeChunked(self): - self.__init() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalDefMode(self): - self.__initWithOptional() - assert decoder.decode( - ints2octs((48, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionaIndefMode(self): - self.__initWithOptional() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 0, 0)), - asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalDefModeChunked(self): - self.__initWithOptional() - assert decoder.decode( - ints2octs((48, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)), - asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalIndefModeChunked(self): - self.__initWithOptional() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)), - asn1Spec=self.s - ) == (self.s, null) - - def testWithDefaultedDefMode(self): - self.__initWithDefaulted() - assert decoder.decode( - ints2octs((48, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s - ) == (self.s, null) - - def testWithDefaultedIndefMode(self): - self.__initWithDefaulted() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testWithDefaultedDefModeChunked(self): - self.__initWithDefaulted() - assert decoder.decode( - ints2octs((48, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s - ) == (self.s, null) - - def testWithDefaultedIndefModeChunked(self): - self.__initWithDefaulted() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalAndDefaultedDefMode(self): - self.__initWithOptionalAndDefaulted() - assert decoder.decode( - ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalAndDefaultedIndefMode(self): - self.__initWithOptionalAndDefaulted() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalAndDefaultedDefModeChunked(self): - self.__initWithOptionalAndDefaulted() - assert decoder.decode( - ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)), asn1Spec=self.s - ) == (self.s, null) - - def testWithOptionalAndDefaultedIndefModeChunked(self): - self.__initWithOptionalAndDefaulted() - assert decoder.decode( - ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s - ) == (self.s, null) - -class ChoiceDecoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Choice(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null(null)), - namedtype.NamedType('number', univ.Integer(0)), - namedtype.NamedType('string', univ.OctetString()) - )) - - def testBySpec(self): - self.s.setComponentByPosition(0, univ.Null(null)) - assert decoder.decode( - ints2octs((5, 0)), asn1Spec=self.s - ) == (self.s, null) - - def testWithoutSpec(self): - self.s.setComponentByPosition(0, univ.Null(null)) - assert decoder.decode(ints2octs((5, 0))) == (self.s, null) - assert decoder.decode(ints2octs((5, 0))) == (univ.Null(null), null) - - def testUndefLength(self): - self.s.setComponentByPosition(2, univ.OctetString('abcdefgh')) - assert decoder.decode(ints2octs((36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0)), asn1Spec=self.s) == (self.s, null) - - def testExplicitTag(self): - s = self.s.subtype(explicitTag=tag.Tag(tag.tagClassContext, - tag.tagFormatConstructed, 4)) - s.setComponentByPosition(0, univ.Null(null)) - assert decoder.decode(ints2octs((164, 2, 5, 0)), asn1Spec=s) == (s, null) - - def testExplicitTagUndefLength(self): - s = self.s.subtype(explicitTag=tag.Tag(tag.tagClassContext, - tag.tagFormatConstructed, 4)) - s.setComponentByPosition(0, univ.Null(null)) - assert decoder.decode(ints2octs((164, 128, 5, 0, 0, 0)), asn1Spec=s) == (s, null) - -class AnyDecoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Any() - - def testByUntagged(self): - assert decoder.decode( - ints2octs((4, 3, 102, 111, 120)), asn1Spec=self.s - ) == (univ.Any('\004\003fox'), null) - - def testTaggedEx(self): - s = univ.Any('\004\003fox').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) - assert decoder.decode(ints2octs((164, 5, 4, 3, 102, 111, 120)), asn1Spec=s) == (s, null) - - def testTaggedIm(self): - s = univ.Any('\004\003fox').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) - assert decoder.decode(ints2octs((132, 5, 4, 3, 102, 111, 120)), asn1Spec=s) == (s, null) - - def testByUntaggedIndefMode(self): - assert decoder.decode( - ints2octs((4, 3, 102, 111, 120)), asn1Spec=self.s - ) == (univ.Any('\004\003fox'), null) - - def testTaggedExIndefMode(self): - s = univ.Any('\004\003fox').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) - assert decoder.decode(ints2octs((164, 128, 4, 3, 102, 111, 120, 0, 0)), asn1Spec=s) == (s, null) - - def testTaggedImIndefMode(self): - s = univ.Any('\004\003fox').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) - assert decoder.decode(ints2octs((164, 128, 4, 3, 102, 111, 120, 0, 0)), asn1Spec=s) == (s, null) - - def testByUntaggedSubst(self): - assert decoder.decode( - ints2octs((4, 3, 102, 111, 120)), - asn1Spec=self.s, - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((4, 3, 102, 111, 120)), 5) - - def testTaggedExSubst(self): - assert decoder.decode( - ints2octs((164, 5, 4, 3, 102, 111, 120)), - asn1Spec=self.s, - substrateFun=lambda a,b,c: (b,c) - ) == (ints2octs((164, 5, 4, 3, 102, 111, 120)), 7) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/ber/test_encoder.py b/third_party/python/pyasn1/test/codec/ber/test_encoder.py deleted file mode 100644 index bfb3f618c7a8..000000000000 --- a/third_party/python/pyasn1/test/codec/ber/test_encoder.py +++ /dev/null @@ -1,338 +0,0 @@ -from pyasn1.type import tag, namedtype, univ -from pyasn1.codec.ber import encoder -from pyasn1.compat.octets import ints2octs -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class LargeTagEncoderTestCase(unittest.TestCase): - def setUp(self): - self.o = univ.Integer().subtype( - value=1, explicitTag=tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0xdeadbeaf) - ) - def testEncoder(self): - assert encoder.encode(self.o) == ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1)) - -class IntegerEncoderTestCase(unittest.TestCase): - def testPosInt(self): - assert encoder.encode(univ.Integer(12)) == ints2octs((2, 1, 12)) - - def testNegInt(self): - assert encoder.encode(univ.Integer(-12)) == ints2octs((2, 1, 244)) - - def testZero(self): - assert encoder.encode(univ.Integer(0)) == ints2octs((2, 1, 0)) - - def testCompactZero(self): - encoder.IntegerEncoder.supportCompactZero = True - substrate = encoder.encode(univ.Integer(0)) - encoder.IntegerEncoder.supportCompactZero = False - assert substrate == ints2octs((2, 0)) - - def testMinusOne(self): - assert encoder.encode(univ.Integer(-1)) == ints2octs((2, 1, 255)) - - def testPosLong(self): - assert encoder.encode( - univ.Integer(0xffffffffffffffff) - ) == ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255)) - - def testNegLong(self): - assert encoder.encode( - univ.Integer(-0xffffffffffffffff) - ) == ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1)) - -class BooleanEncoderTestCase(unittest.TestCase): - def testTrue(self): - assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 1)) - - def testFalse(self): - assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0)) - -class BitStringEncoderTestCase(unittest.TestCase): - def setUp(self): - self.b = univ.BitString((1,0,1,0,1,0,0,1,1,0,0,0,1,0,1)) - - def testDefMode(self): - assert encoder.encode(self.b) == ints2octs((3, 3, 1, 169, 138)) - - def testIndefMode(self): - assert encoder.encode( - self.b, defMode=0 - ) == ints2octs((3, 3, 1, 169, 138)) - - def testDefModeChunked(self): - assert encoder.encode( - self.b, maxChunkSize=1 - ) == ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)) - - def testIndefModeChunked(self): - assert encoder.encode( - self.b, defMode=0, maxChunkSize=1 - ) == ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)) - - def testEmptyValue(self): - assert encoder.encode(univ.BitString(())) == ints2octs((3, 1, 0)) - -class OctetStringEncoderTestCase(unittest.TestCase): - def setUp(self): - self.o = univ.OctetString('Quick brown fox') - - def testDefMode(self): - assert encoder.encode(self.o) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - - def testIndefMode(self): - assert encoder.encode( - self.o, defMode=0 - ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - - def testDefModeChunked(self): - assert encoder.encode( - self.o, maxChunkSize=4 - ) == ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)) - - def testIndefModeChunked(self): - assert encoder.encode( - self.o, defMode=0, maxChunkSize=4 - ) == ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)) - -class ExpTaggedOctetStringEncoderTestCase(unittest.TestCase): - def setUp(self): - self.o = univ.OctetString().subtype( - value='Quick brown fox', - explicitTag=tag.Tag(tag.tagClassApplication,tag.tagFormatSimple,5) - ) - def testDefMode(self): - assert encoder.encode(self.o) == ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - - def testIndefMode(self): - assert encoder.encode( - self.o, defMode=0 - ) == ints2octs((101, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0)) - - def testDefModeChunked(self): - assert encoder.encode( - self.o, defMode=1, maxChunkSize=4 - ) == ints2octs((101, 25, 36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)) - - def testIndefModeChunked(self): - assert encoder.encode( - self.o, defMode=0, maxChunkSize=4 - ) == ints2octs((101, 128, 36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0, 0, 0)) - -class NullEncoderTestCase(unittest.TestCase): - def testNull(self): - assert encoder.encode(univ.Null('')) == ints2octs((5, 0)) - -class ObjectIdentifierEncoderTestCase(unittest.TestCase): - def testNull(self): - assert encoder.encode( - univ.ObjectIdentifier((1,3,6,0,0xffffe)) - ) == ints2octs((6, 6, 43, 6, 0, 191, 255, 126)) - -class RealEncoderTestCase(unittest.TestCase): - def testChar(self): - assert encoder.encode( - univ.Real((123, 10, 11)) - ) == ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49)) - - def testBin1(self): - assert encoder.encode( - univ.Real((1101, 2, 11)) - ) == ints2octs((9, 4, 128, 11, 4, 77)) - - def testBin2(self): - assert encoder.encode( - univ.Real((1101, 2, -11)) - ) == ints2octs((9, 4, 128, 245, 4, 77)) - - def testPlusInf(self): - assert encoder.encode(univ.Real('inf')) == ints2octs((9, 1, 64)) - - def testMinusInf(self): - assert encoder.encode(univ.Real('-inf')) == ints2octs((9, 1, 65)) - - def testZero(self): - assert encoder.encode(univ.Real(0)) == ints2octs((9, 0)) - -class SequenceEncoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Sequence(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null('')), - namedtype.OptionalNamedType('first-name', univ.OctetString('')), - namedtype.DefaultedNamedType('age', univ.Integer(33)), - )) - - def __init(self): - self.s.clear() - self.s.setComponentByPosition(0) - - def __initWithOptional(self): - self.s.clear() - self.s.setComponentByPosition(0) - self.s.setComponentByPosition(1, 'quick brown') - - def __initWithDefaulted(self): - self.s.clear() - self.s.setComponentByPosition(0) - self.s.setComponentByPosition(2, 1) - - def __initWithOptionalAndDefaulted(self): - self.s.clear() - self.s.setComponentByPosition(0, univ.Null('')) - self.s.setComponentByPosition(1, univ.OctetString('quick brown')) - self.s.setComponentByPosition(2, univ.Integer(1)) - - def testDefMode(self): - self.__init() - assert encoder.encode(self.s) == ints2octs((48, 2, 5, 0)) - - def testIndefMode(self): - self.__init() - assert encoder.encode( - self.s, defMode=0 - ) == ints2octs((48, 128, 5, 0, 0, 0)) - - def testDefModeChunked(self): - self.__init() - assert encoder.encode( - self.s, defMode=1, maxChunkSize=4 - ) == ints2octs((48, 2, 5, 0)) - - def testIndefModeChunked(self): - self.__init() - assert encoder.encode( - self.s, defMode=0, maxChunkSize=4 - ) == ints2octs((48, 128, 5, 0, 0, 0)) - - def testWithOptionalDefMode(self): - self.__initWithOptional() - assert encoder.encode(self.s) == ints2octs((48, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) - - def testWithOptionalIndefMode(self): - self.__initWithOptional() - assert encoder.encode( - self.s, defMode=0 - ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) - - def testWithOptionalDefModeChunked(self): - self.__initWithOptional() - assert encoder.encode( - self.s, defMode=1, maxChunkSize=4 - ) == ints2octs((48, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) - - def testWithOptionalIndefModeChunked(self): - self.__initWithOptional() - assert encoder.encode( - self.s, defMode=0, maxChunkSize=4 - ) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) - - def testWithDefaultedDefMode(self): - self.__initWithDefaulted() - assert encoder.encode(self.s) == ints2octs((48, 5, 5, 0, 2, 1, 1)) - - def testWithDefaultedIndefMode(self): - self.__initWithDefaulted() - assert encoder.encode( - self.s, defMode=0 - ) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)) - - def testWithDefaultedDefModeChunked(self): - self.__initWithDefaulted() - assert encoder.encode( - self.s, defMode=1, maxChunkSize=4 - ) == ints2octs((48, 5, 5, 0, 2, 1, 1)) - - def testWithDefaultedIndefModeChunked(self): - self.__initWithDefaulted() - assert encoder.encode( - self.s, defMode=0, maxChunkSize=4 - ) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)) - - def testWithOptionalAndDefaultedDefMode(self): - self.__initWithOptionalAndDefaulted() - assert encoder.encode(self.s) == ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) - - def testWithOptionalAndDefaultedIndefMode(self): - self.__initWithOptionalAndDefaulted() - assert encoder.encode( - self.s, defMode=0 - ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) - - def testWithOptionalAndDefaultedDefModeChunked(self): - self.__initWithOptionalAndDefaulted() - assert encoder.encode( - self.s, defMode=1, maxChunkSize=4 - ) == ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) - - def testWithOptionalAndDefaultedIndefModeChunked(self): - self.__initWithOptionalAndDefaulted() - assert encoder.encode( - self.s, defMode=0, maxChunkSize=4 - ) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) - -class ChoiceEncoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Choice(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null('')), - namedtype.NamedType('number', univ.Integer(0)), - namedtype.NamedType('string', univ.OctetString()) - )) - - def testEmpty(self): - try: - encoder.encode(self.s) - except PyAsn1Error: - pass - else: - assert 0, 'encoded unset choice' - - def testFilled(self): - self.s.setComponentByPosition(0, univ.Null('')) - assert encoder.encode(self.s) == ints2octs((5, 0)) - - def testTagged(self): - s = self.s.subtype( - explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,4) - ) - s.setComponentByPosition(0, univ.Null('')) - assert encoder.encode(s) == ints2octs((164, 2, 5, 0)) - - def testUndefLength(self): - self.s.setComponentByPosition(2, univ.OctetString('abcdefgh')) - assert encoder.encode(self.s, defMode=False, maxChunkSize=3) == ints2octs((36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0)) - - def testTaggedUndefLength(self): - s = self.s.subtype( - explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,4) - ) - s.setComponentByPosition(2, univ.OctetString('abcdefgh')) - assert encoder.encode(s, defMode=False, maxChunkSize=3) == ints2octs((164, 128, 36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0, 0, 0)) - -class AnyEncoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Any(encoder.encode(univ.OctetString('fox'))) - - def testUntagged(self): - assert encoder.encode(self.s) == ints2octs((4, 3, 102, 111, 120)) - - def testTaggedEx(self): - s = self.s.subtype( - explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4) - ) - assert encoder.encode(s) == ints2octs((164, 5, 4, 3, 102, 111, 120)) - - def testTaggedIm(self): - s = self.s.subtype( - implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4) - ) - assert encoder.encode(s) == ints2octs((132, 5, 4, 3, 102, 111, 120)) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/cer/suite.py b/third_party/python/pyasn1/test/codec/cer/suite.py deleted file mode 100644 index 49d682918b8d..000000000000 --- a/third_party/python/pyasn1/test/codec/cer/suite.py +++ /dev/null @@ -1,22 +0,0 @@ -from sys import path, version_info -from os.path import sep -path.insert(1, path[0]+sep+'cer') -import test_encoder, test_decoder -from pyasn1.error import PyAsn1Error -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -suite = unittest.TestSuite() -loader = unittest.TestLoader() -for m in (test_encoder, test_decoder): - suite.addTest(loader.loadTestsFromModule(m)) - -def runTests(): unittest.TextTestRunner(verbosity=2).run(suite) - -if __name__ == '__main__': runTests() diff --git a/third_party/python/pyasn1/test/codec/cer/test_decoder.py b/third_party/python/pyasn1/test/codec/cer/test_decoder.py deleted file mode 100644 index 7195b72e096e..000000000000 --- a/third_party/python/pyasn1/test/codec/cer/test_decoder.py +++ /dev/null @@ -1,31 +0,0 @@ -from pyasn1.type import univ -from pyasn1.codec.cer import decoder -from pyasn1.compat.octets import ints2octs, str2octs, null -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class BooleanDecoderTestCase(unittest.TestCase): - def testTrue(self): - assert decoder.decode(ints2octs((1, 1, 255))) == (1, null) - def testFalse(self): - assert decoder.decode(ints2octs((1, 1, 0))) == (0, null) - -class OctetStringDecoderTestCase(unittest.TestCase): - def testShortMode(self): - assert decoder.decode( - ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), - ) == (str2octs('Quick brown fox'), null) - def testLongMode(self): - assert decoder.decode( - ints2octs((36, 128, 4, 130, 3, 232) + (81,)*1000 + (4, 1, 81, 0, 0)) - ) == (str2octs('Q'*1001), null) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/cer/test_encoder.py b/third_party/python/pyasn1/test/codec/cer/test_encoder.py deleted file mode 100644 index a4f80aa20e58..000000000000 --- a/third_party/python/pyasn1/test/codec/cer/test_encoder.py +++ /dev/null @@ -1,107 +0,0 @@ -from pyasn1.type import namedtype, univ -from pyasn1.codec.cer import encoder -from pyasn1.compat.octets import ints2octs -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class BooleanEncoderTestCase(unittest.TestCase): - def testTrue(self): - assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 255)) - def testFalse(self): - assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0)) - -class BitStringEncoderTestCase(unittest.TestCase): - def testShortMode(self): - assert encoder.encode( - univ.BitString((1,0)*501) - ) == ints2octs((3, 127, 6) + (170,) * 125 + (128,)) - - def testLongMode(self): - assert encoder.encode( - univ.BitString((1,0)*501) - ) == ints2octs((3, 127, 6) + (170,) * 125 + (128,)) - -class OctetStringEncoderTestCase(unittest.TestCase): - def testShortMode(self): - assert encoder.encode( - univ.OctetString('Quick brown fox') - ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - def testLongMode(self): - assert encoder.encode( - univ.OctetString('Q'*1001) - ) == ints2octs((36, 128, 4, 130, 3, 232) + (81,)*1000 + (4, 1, 81, 0, 0)) - -class SetEncoderTestCase(unittest.TestCase): - def setUp(self): - self.s = univ.Set(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null('')), - namedtype.OptionalNamedType('first-name', univ.OctetString('')), - namedtype.DefaultedNamedType('age', univ.Integer(33)) - )) - - def __init(self): - self.s.clear() - self.s.setComponentByPosition(0) - def __initWithOptional(self): - self.s.clear() - self.s.setComponentByPosition(0) - self.s.setComponentByPosition(1, 'quick brown') - - def __initWithDefaulted(self): - self.s.clear() - self.s.setComponentByPosition(0) - self.s.setComponentByPosition(2, 1) - - def __initWithOptionalAndDefaulted(self): - self.s.clear() - self.s.setComponentByPosition(0, univ.Null('')) - self.s.setComponentByPosition(1, univ.OctetString('quick brown')) - self.s.setComponentByPosition(2, univ.Integer(1)) - - def testIndefMode(self): - self.__init() - assert encoder.encode(self.s) == ints2octs((49, 128, 5, 0, 0, 0)) - - def testWithOptionalIndefMode(self): - self.__initWithOptional() - assert encoder.encode( - self.s - ) == ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) - - def testWithDefaultedIndefMode(self): - self.__initWithDefaulted() - assert encoder.encode( - self.s - ) == ints2octs((49, 128, 2, 1, 1, 5, 0, 0, 0)) - - def testWithOptionalAndDefaultedIndefMode(self): - self.__initWithOptionalAndDefaulted() - assert encoder.encode( - self.s - ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) - -class SetWithChoiceEncoderTestCase(unittest.TestCase): - def setUp(self): - c = univ.Choice(componentType=namedtype.NamedTypes( - namedtype.NamedType('actual', univ.Boolean(0)) - )) - self.s = univ.Set(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null('')), - namedtype.NamedType('status', c) - )) - - def testIndefMode(self): - self.s.setComponentByPosition(0) - self.s.setComponentByName('status') - self.s.getComponentByName('status').setComponentByPosition(0, 1) - assert encoder.encode(self.s) == ints2octs((49, 128, 1, 1, 255, 5, 0, 0, 0)) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/der/suite.py b/third_party/python/pyasn1/test/codec/der/suite.py deleted file mode 100644 index 7af83bf94fa7..000000000000 --- a/third_party/python/pyasn1/test/codec/der/suite.py +++ /dev/null @@ -1,22 +0,0 @@ -from sys import path, version_info -from os.path import sep -path.insert(1, path[0]+sep+'der') -import test_encoder, test_decoder -from pyasn1.error import PyAsn1Error -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -suite = unittest.TestSuite() -loader = unittest.TestLoader() -for m in (test_encoder, test_decoder): - suite.addTest(loader.loadTestsFromModule(m)) - -def runTests(): unittest.TextTestRunner(verbosity=2).run(suite) - -if __name__ == '__main__': runTests() diff --git a/third_party/python/pyasn1/test/codec/der/test_decoder.py b/third_party/python/pyasn1/test/codec/der/test_decoder.py deleted file mode 100644 index 5c9a1948b993..000000000000 --- a/third_party/python/pyasn1/test/codec/der/test_decoder.py +++ /dev/null @@ -1,20 +0,0 @@ -from pyasn1.type import univ -from pyasn1.codec.der import decoder -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class OctetStringDecoderTestCase(unittest.TestCase): - def testShortMode(self): - assert decoder.decode( - '\004\017Quick brown fox'.encode() - ) == ('Quick brown fox'.encode(), ''.encode()) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/der/test_encoder.py b/third_party/python/pyasn1/test/codec/der/test_encoder.py deleted file mode 100644 index 787da7bec31d..000000000000 --- a/third_party/python/pyasn1/test/codec/der/test_encoder.py +++ /dev/null @@ -1,44 +0,0 @@ -from pyasn1.type import namedtype, univ -from pyasn1.codec.der import encoder -from pyasn1.compat.octets import ints2octs -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class OctetStringEncoderTestCase(unittest.TestCase): - def testShortMode(self): - assert encoder.encode( - univ.OctetString('Quick brown fox') - ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) - -class BitStringEncoderTestCase(unittest.TestCase): - def testShortMode(self): - assert encoder.encode( - univ.BitString((1,)) - ) == ints2octs((3, 2, 7, 128)) - -class SetWithChoiceEncoderTestCase(unittest.TestCase): - def setUp(self): - c = univ.Choice(componentType=namedtype.NamedTypes( - namedtype.NamedType('name', univ.OctetString('')), - namedtype.NamedType('amount', univ.Integer(0)) - )) - self.s = univ.Set(componentType=namedtype.NamedTypes( - namedtype.NamedType('place-holder', univ.Null('')), - namedtype.NamedType('status', c) - )) - - def testDefMode(self): - self.s.setComponentByPosition(0) - self.s.setComponentByName('status') - self.s.getComponentByName('status').setComponentByPosition(0, 'ann') - assert encoder.encode(self.s) == ints2octs((49, 7, 4, 3, 97, 110, 110, 5, 0)) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/suite.py b/third_party/python/pyasn1/test/codec/suite.py deleted file mode 100644 index 93ff06381838..000000000000 --- a/third_party/python/pyasn1/test/codec/suite.py +++ /dev/null @@ -1,29 +0,0 @@ -from sys import path, version_info -from os.path import sep -path.insert(1, path[0]+sep+'codec'+sep+'ber') -import ber.suite -path.insert(1, path[0]+sep+'codec'+sep+'cer') -import cer.suite -path.insert(1, path[0]+sep+'codec'+sep+'der') -import der.suite -from pyasn1.error import PyAsn1Error -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -suite = unittest.TestSuite() -for m in ( - ber.suite, - cer.suite, - der.suite - ): - suite.addTest(getattr(m, 'suite')) - -def runTests(): unittest.TextTestRunner(verbosity=2).run(suite) - -if __name__ == '__main__': runTests() diff --git a/third_party/python/pyasn1/test/suite.py b/third_party/python/pyasn1/test/suite.py deleted file mode 100644 index b4d80e864a96..000000000000 --- a/third_party/python/pyasn1/test/suite.py +++ /dev/null @@ -1,26 +0,0 @@ -from sys import path, version_info -from os.path import sep -path.insert(1, path[0]+sep+'type') -import type.suite -path.insert(1, path[0]+sep+'codec') -import codec.suite -from pyasn1.error import PyAsn1Error -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -suite = unittest.TestSuite() -for m in ( - type.suite, - codec.suite - ): - suite.addTest(getattr(m, 'suite')) - -def runTests(): unittest.TextTestRunner(verbosity=2).run(suite) - -if __name__ == '__main__': runTests() diff --git a/third_party/python/pyasn1/test/type/suite.py b/third_party/python/pyasn1/test/type/suite.py deleted file mode 100644 index bc4b48685fb2..000000000000 --- a/third_party/python/pyasn1/test/type/suite.py +++ /dev/null @@ -1,20 +0,0 @@ -import test_tag, test_constraint, test_namedtype, test_univ -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -suite = unittest.TestSuite() -loader = unittest.TestLoader() -for m in (test_tag, test_constraint, test_namedtype, test_univ): - suite.addTest(loader.loadTestsFromModule(m)) - -def runTests(): unittest.TextTestRunner(verbosity=2).run(suite) - -if __name__ == '__main__': runTests() diff --git a/third_party/python/pyasn1/test/type/test_namedtype.py b/third_party/python/pyasn1/test/type/test_namedtype.py deleted file mode 100644 index 3a4f305994f0..000000000000 --- a/third_party/python/pyasn1/test/type/test_namedtype.py +++ /dev/null @@ -1,87 +0,0 @@ -from pyasn1.type import namedtype, univ -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class NamedTypeCaseBase(unittest.TestCase): - def setUp(self): - self.e = namedtype.NamedType('age', univ.Integer()) - def testIter(self): - n, t = self.e - assert n == 'age' or t == univ.Integer(), 'unpack fails' - -class NamedTypesCaseBase(unittest.TestCase): - def setUp(self): - self.e = namedtype.NamedTypes( - namedtype.NamedType('first-name', univ.OctetString('')), - namedtype.OptionalNamedType('age', univ.Integer(0)), - namedtype.NamedType('family-name', univ.OctetString('')) - ) - def testIter(self): - for t in self.e: - break - else: - assert 0, '__getitem__() fails' - - def testGetTypeByPosition(self): - assert self.e.getTypeByPosition(0) == univ.OctetString(''), \ - 'getTypeByPosition() fails' - - def testGetNameByPosition(self): - assert self.e.getNameByPosition(0) == 'first-name', \ - 'getNameByPosition() fails' - - def testGetPositionByName(self): - assert self.e.getPositionByName('first-name') == 0, \ - 'getPositionByName() fails' - - def testGetTypesNearPosition(self): - assert self.e.getTagMapNearPosition(0).getPosMap() == { - univ.OctetString.tagSet: univ.OctetString('') - } - assert self.e.getTagMapNearPosition(1).getPosMap() == { - univ.Integer.tagSet: univ.Integer(0), - univ.OctetString.tagSet: univ.OctetString('') - } - assert self.e.getTagMapNearPosition(2).getPosMap() == { - univ.OctetString.tagSet: univ.OctetString('') - } - - def testGetTagMap(self): - assert self.e.getTagMap().getPosMap() == { - univ.OctetString.tagSet: univ.OctetString(''), - univ.Integer.tagSet: univ.Integer(0) - } - - def testGetTagMapWithDups(self): - try: - self.e.getTagMap(1) - except PyAsn1Error: - pass - else: - assert 0, 'Duped types not noticed' - - def testGetPositionNearType(self): - assert self.e.getPositionNearType(univ.OctetString.tagSet, 0) == 0 - assert self.e.getPositionNearType(univ.Integer.tagSet, 1) == 1 - assert self.e.getPositionNearType(univ.OctetString.tagSet, 2) == 2 - -class OrderedNamedTypesCaseBase(unittest.TestCase): - def setUp(self): - self.e = namedtype.NamedTypes( - namedtype.NamedType('first-name', univ.OctetString('')), - namedtype.NamedType('age', univ.Integer(0)) - ) - - def testGetTypeByPosition(self): - assert self.e.getTypeByPosition(0) == univ.OctetString(''), \ - 'getTypeByPosition() fails' - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/type/test_univ.py b/third_party/python/pyasn1/test/type/test_univ.py deleted file mode 100644 index 3eedcf26a6ac..000000000000 --- a/third_party/python/pyasn1/test/type/test_univ.py +++ /dev/null @@ -1,479 +0,0 @@ -from pyasn1.type import univ, tag, constraint, namedtype, namedval, error -from pyasn1.compat.octets import str2octs, ints2octs -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: - import unittest - -class IntegerTestCase(unittest.TestCase): - def testStr(self): assert str(univ.Integer(1)) in ('1','1L'),'str() fails' - def testAnd(self): assert univ.Integer(1) & 0 == 0, '__and__() fails' - def testOr(self): assert univ.Integer(1) | 0 == 1, '__or__() fails' - def testXor(self): assert univ.Integer(1) ^ 0 == 1, '__xor__() fails' - def testRand(self): assert 0 & univ.Integer(1) == 0, '__rand__() fails' - def testRor(self): assert 0 | univ.Integer(1) == 1, '__ror__() fails' - def testRxor(self): assert 0 ^ univ.Integer(1) == 1, '__rxor__() fails' - def testAdd(self): assert univ.Integer(-4) + 6 == 2, '__add__() fails' - def testRadd(self): assert 4 + univ.Integer(5) == 9, '__radd__() fails' - def testSub(self): assert univ.Integer(3) - 6 == -3, '__sub__() fails' - def testRsub(self): assert 6 - univ.Integer(3) == 3, '__rsub__() fails' - def testMul(self): assert univ.Integer(3) * -3 == -9, '__mul__() fails' - def testRmul(self): assert 2 * univ.Integer(3) == 6, '__rmul__() fails' - def testDiv(self): assert univ.Integer(3) / 2 == 1, '__div__() fails' - def testRdiv(self): assert 6 / univ.Integer(3) == 2, '__rdiv__() fails' - def testMod(self): assert univ.Integer(3) % 2 == 1, '__mod__() fails' - def testRmod(self): assert 4 % univ.Integer(3) == 1, '__rmod__() fails' - def testPow(self): assert univ.Integer(3) ** 2 == 9, '__pow__() fails' - def testRpow(self): assert 2 ** univ.Integer(2) == 4, '__rpow__() fails' - def testLshift(self): assert univ.Integer(1) << 1 == 2, '<< fails' - def testRshift(self): assert univ.Integer(2) >> 1 == 1, '>> fails' - def testInt(self): assert int(univ.Integer(3)) == 3, '__int__() fails' - def testLong(self): assert int(univ.Integer(8)) == 8, '__long__() fails' - def testFloat(self): assert float(univ.Integer(4))==4.0,'__float__() fails' - def testPrettyIn(self): assert univ.Integer('3') == 3, 'prettyIn() fails' - def testTag(self): - assert univ.Integer().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) - ) - def testNamedVals(self): - i = univ.Integer( - 'asn1', namedValues=univ.Integer.namedValues.clone(('asn1', 1)) - ) - assert i == 1, 'named val fails' - assert str(i) != 'asn1', 'named val __str__() fails' - -class BooleanTestCase(unittest.TestCase): - def testTruth(self): - assert univ.Boolean(True) and univ.Boolean(1), 'Truth initializer fails' - def testFalse(self): - assert not univ.Boolean(False) and not univ.Boolean(0), 'False initializer fails' - def testStr(self): - assert str(univ.Boolean(1)) in ('1', '1L'), 'str() fails' - def testTag(self): - assert univ.Boolean().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01) - ) - def testConstraints(self): - try: - univ.Boolean(2) - except error.ValueConstraintError: - pass - else: - assert 0, 'constraint fail' - def testSubtype(self): - assert univ.Integer().subtype( - value=1, - implicitTag=tag.Tag(tag.tagClassPrivate,tag.tagFormatSimple,2), - subtypeSpec=constraint.SingleValueConstraint(1,3) - ) == univ.Integer( - value=1, - tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate, - tag.tagFormatSimple,2)), - subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1,3)) - ) - -class BitStringTestCase(unittest.TestCase): - def setUp(self): - self.b = univ.BitString( - namedValues=namedval.NamedValues(('Active', 0), ('Urgent', 1)) - ) - def testSet(self): - assert self.b.clone('Active') == (1,) - assert self.b.clone("'1010100110001010'B") == (1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0) - assert self.b.clone("'A98A'H") == (1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0) - assert self.b.clone((1,0,1)) == (1,0,1) - def testStr(self): - assert str(self.b.clone('Urgent,Active')) == '(1, 1)' - def testRepr(self): - assert repr(self.b.clone('Urgent,Active')) == 'BitString("\'11\'B")' - def testTag(self): - assert univ.BitString().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) - ) - def testLen(self): assert len(self.b.clone("'A98A'H")) == 16 - def testIter(self): - assert self.b.clone("'A98A'H")[0] == 1 - assert self.b.clone("'A98A'H")[1] == 0 - assert self.b.clone("'A98A'H")[2] == 1 - -class OctetStringTestCase(unittest.TestCase): - def testInit(self): - assert univ.OctetString(str2octs('abcd')) == str2octs('abcd'), '__init__() fails' - def testBinStr(self): - assert univ.OctetString(binValue="1000010111101110101111000000111011") == ints2octs((133, 238, 188, 14, 192)), 'bin init fails' - def testHexStr(self): - assert univ.OctetString(hexValue="FA9823C43E43510DE3422") == ints2octs((250, 152, 35, 196, 62, 67, 81, 13, 227, 66, 32)), 'hex init fails' - def testTuple(self): - assert univ.OctetString((1,2,3,4,5)) == ints2octs((1,2,3,4,5)), 'tuple init failed' - def testStr(self): - assert str(univ.OctetString('q')) == 'q', '__str__() fails' - def testSeq(self): - assert univ.OctetString('q')[0] == str2octs('q')[0],'__getitem__() fails' - def testAsOctets(self): - assert univ.OctetString('abcd').asOctets() == str2octs('abcd'), 'testAsOctets() fails' - def testAsInts(self): - assert univ.OctetString('abcd').asNumbers() == (97, 98, 99, 100), 'testAsNumbers() fails' - - def testEmpty(self): - try: - str(univ.OctetString()) - except PyAsn1Error: - pass - else: - assert 0, 'empty OctetString() not reported' - - def testAdd(self): - assert univ.OctetString('') + 'q' == str2octs('q'), '__add__() fails' - def testRadd(self): - assert 'b' + univ.OctetString('q') == str2octs('bq'), '__radd__() fails' - def testMul(self): - assert univ.OctetString('a') * 2 == str2octs('aa'), '__mul__() fails' - def testRmul(self): - assert 2 * univ.OctetString('b') == str2octs('bb'), '__rmul__() fails' - def testTag(self): - assert univ.OctetString().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) - ) - -class Null(unittest.TestCase): - def testStr(self): assert str(univ.Null('')) == '', 'str() fails' - def testTag(self): - assert univ.Null().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) - ) - def testConstraints(self): - try: - univ.Null(2) - except error.ValueConstraintError: - pass - else: - assert 0, 'constraint fail' - -class RealTestCase(unittest.TestCase): - def testStr(self): assert str(univ.Real(1.0)) == '1.0','str() fails' - def testRepr(self): assert repr(univ.Real(-4.1)) == 'Real((-41, 10, -1))','repr() fails' - def testAdd(self): assert univ.Real(-4.1) + 1.4 == -2.7, '__add__() fails' - def testRadd(self): assert 4 + univ.Real(0.5) == 4.5, '__radd__() fails' - def testSub(self): assert univ.Real(3.9) - 1.7 == 2.2, '__sub__() fails' - def testRsub(self): assert 6.1 - univ.Real(0.1) == 6, '__rsub__() fails' - def testMul(self): assert univ.Real(3.0) * -3 == -9, '__mul__() fails' - def testRmul(self): assert 2 * univ.Real(3.0) == 6, '__rmul__() fails' - def testDiv(self): assert univ.Real(3.0) / 2 == 1.5, '__div__() fails' - def testRdiv(self): assert 6 / univ.Real(3.0) == 2, '__rdiv__() fails' - def testMod(self): assert univ.Real(3.0) % 2 == 1, '__mod__() fails' - def testRmod(self): assert 4 % univ.Real(3.0) == 1, '__rmod__() fails' - def testPow(self): assert univ.Real(3.0) ** 2 == 9, '__pow__() fails' - def testRpow(self): assert 2 ** univ.Real(2.0) == 4, '__rpow__() fails' - def testInt(self): assert int(univ.Real(3.0)) == 3, '__int__() fails' - def testLong(self): assert int(univ.Real(8.0)) == 8, '__long__() fails' - def testFloat(self): assert float(univ.Real(4.0))==4.0,'__float__() fails' - def testPrettyIn(self): assert univ.Real((3,10,0)) == 3, 'prettyIn() fails' - # infinite float values - def testStrInf(self): - assert str(univ.Real('inf')) == 'inf','str() fails' - def testReprInf(self): - assert repr(univ.Real('inf')) == 'Real(\'inf\')','repr() fails' - def testAddInf(self): - assert univ.Real('inf') + 1 == float('inf'), '__add__() fails' - def testRaddInf(self): - assert 1 + univ.Real('inf') == float('inf'), '__radd__() fails' - def testIntInf(self): - try: - assert int(univ.Real('inf')) - except OverflowError: - pass - else: - assert 0, '__int__() fails' - def testLongInf(self): - try: - assert int(univ.Real('inf')) - except OverflowError: - pass - else: - assert 0, '__long__() fails' - assert int(univ.Real(8.0)) == 8, '__long__() fails' - def testFloatInf(self): - assert float(univ.Real('-inf')) == float('-inf'),'__float__() fails' - def testPrettyInInf(self): - assert univ.Real(float('inf')) == float('inf'), 'prettyIn() fails' - def testPlusInf(self): - assert univ.Real('inf').isPlusInfinity(), 'isPlusInfinity failed' - def testMinusInf(self): - assert univ.Real('-inf').isMinusInfinity(), 'isMinusInfinity failed' - - def testTag(self): - assert univ.Real().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) - ) - -class ObjectIdentifier(unittest.TestCase): - def testStr(self): - assert str(univ.ObjectIdentifier((1,3,6))) == '1.3.6' - def testEq(self): - assert univ.ObjectIdentifier((1,3,6)) == (1,3,6), '__cmp__() fails' - def testAdd(self): - assert univ.ObjectIdentifier((1,3)) + (6,)==(1,3,6),'__add__() fails' - def testRadd(self): - assert (1,) + univ.ObjectIdentifier((3,6))==(1,3,6),'__radd__() fails' - def testLen(self): - assert len(univ.ObjectIdentifier((1,3))) == 2,'__len__() fails' - def testPrefix(self): - o = univ.ObjectIdentifier('1.3.6') - assert o.isPrefixOf((1,3,6)), 'isPrefixOf() fails' - assert o.isPrefixOf((1,3,6,1)), 'isPrefixOf() fails' - assert not o.isPrefixOf((1,3)), 'isPrefixOf() fails' - def testInput(self): - assert univ.ObjectIdentifier('1.3.6')==(1,3,6),'prettyIn() fails' - def testTag(self): - assert univ.ObjectIdentifier().getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) - ) - -class SequenceOf(unittest.TestCase): - def setUp(self): - self.s1 = univ.SequenceOf( - componentType=univ.OctetString('') - ) - self.s2 = self.s1.clone() - def testTag(self): - assert self.s1.getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ), 'wrong tagSet' - def testSeq(self): - self.s1.setComponentByPosition(0, univ.OctetString('abc')) - assert self.s1[0] == str2octs('abc'), 'set by idx fails' - self.s1[0] = 'cba' - assert self.s1[0] == str2octs('cba'), 'set by idx fails' - def testCmp(self): - self.s1.clear() - self.s1.setComponentByPosition(0, 'abc') - self.s2.clear() - self.s2.setComponentByPosition(0, univ.OctetString('abc')) - assert self.s1 == self.s2, '__cmp__() fails' - def testSubtypeSpec(self): - s = self.s1.clone(subtypeSpec=constraint.ConstraintsUnion( - constraint.SingleValueConstraint(str2octs('abc')) - )) - try: - s.setComponentByPosition(0, univ.OctetString('abc')) - except: - assert 0, 'constraint fails' - try: - s.setComponentByPosition(1, univ.OctetString('Abc')) - except: - pass - else: - assert 0, 'constraint fails' - def testSizeSpec(self): - s = self.s1.clone(sizeSpec=constraint.ConstraintsUnion( - constraint.ValueSizeConstraint(1,1) - )) - s.setComponentByPosition(0, univ.OctetString('abc')) - try: - s.verifySizeSpec() - except: - assert 0, 'size spec fails' - s.setComponentByPosition(1, univ.OctetString('abc')) - try: - s.verifySizeSpec() - except: - pass - else: - assert 0, 'size spec fails' - def testGetComponentTagMap(self): - assert self.s1.getComponentTagMap().getPosMap() == { - univ.OctetString.tagSet: univ.OctetString('') - } - def testSubtype(self): - self.s1.clear() - assert self.s1.subtype( - implicitTag=tag.Tag(tag.tagClassPrivate,tag.tagFormatSimple,2), - subtypeSpec=constraint.SingleValueConstraint(1,3), - sizeSpec=constraint.ValueSizeConstraint(0,1) - ) == self.s1.clone( - tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate, - tag.tagFormatSimple,2)), - subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1,3)), - sizeSpec=constraint.ValueSizeConstraint(0,1) - ) - def testClone(self): - self.s1.setComponentByPosition(0, univ.OctetString('abc')) - s = self.s1.clone() - assert len(s) == 0 - s = self.s1.clone(cloneValueFlag=1) - assert len(s) == 1 - assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0) - -class Sequence(unittest.TestCase): - def setUp(self): - self.s1 = univ.Sequence(componentType=namedtype.NamedTypes( - namedtype.NamedType('name', univ.OctetString('')), - namedtype.OptionalNamedType('nick', univ.OctetString('')), - namedtype.DefaultedNamedType('age', univ.Integer(34)) - )) - def testTag(self): - assert self.s1.getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ), 'wrong tagSet' - def testById(self): - self.s1.setComponentByName('name', univ.OctetString('abc')) - assert self.s1.getComponentByName('name') == str2octs('abc'), 'set by name fails' - def testByKey(self): - self.s1['name'] = 'abc' - assert self.s1['name'] == str2octs('abc'), 'set by key fails' - def testGetNearPosition(self): - assert self.s1.getComponentTagMapNearPosition(1).getPosMap() == { - univ.OctetString.tagSet: univ.OctetString(''), - univ.Integer.tagSet: univ.Integer(34) - } - assert self.s1.getComponentPositionNearType( - univ.OctetString.tagSet, 1 - ) == 1 - def testGetDefaultComponentByPosition(self): - self.s1.clear() - assert self.s1.getDefaultComponentByPosition(0) == None - assert self.s1.getDefaultComponentByPosition(2) == univ.Integer(34) - def testSetDefaultComponents(self): - self.s1.clear() - assert self.s1.getComponentByPosition(2) == None - self.s1.setComponentByPosition(0, univ.OctetString('Ping')) - self.s1.setComponentByPosition(1, univ.OctetString('Pong')) - self.s1.setDefaultComponents() - assert self.s1.getComponentByPosition(2) == 34 - def testClone(self): - self.s1.setComponentByPosition(0, univ.OctetString('abc')) - self.s1.setComponentByPosition(1, univ.OctetString('def')) - self.s1.setComponentByPosition(2, univ.Integer(123)) - s = self.s1.clone() - assert s.getComponentByPosition(0) != self.s1.getComponentByPosition(0) - assert s.getComponentByPosition(1) != self.s1.getComponentByPosition(1) - assert s.getComponentByPosition(2) != self.s1.getComponentByPosition(2) - s = self.s1.clone(cloneValueFlag=1) - assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0) - assert s.getComponentByPosition(1) == self.s1.getComponentByPosition(1) - assert s.getComponentByPosition(2) == self.s1.getComponentByPosition(2) - -class SetOf(unittest.TestCase): - def setUp(self): - self.s1 = univ.SetOf(componentType=univ.OctetString('')) - def testTag(self): - assert self.s1.getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ), 'wrong tagSet' - def testSeq(self): - self.s1.setComponentByPosition(0, univ.OctetString('abc')) - assert self.s1[0] == str2octs('abc'), 'set by idx fails' - self.s1.setComponentByPosition(0, self.s1[0].clone('cba')) - assert self.s1[0] == str2octs('cba'), 'set by idx fails' - -class Set(unittest.TestCase): - def setUp(self): - self.s1 = univ.Set(componentType=namedtype.NamedTypes( - namedtype.NamedType('name', univ.OctetString('')), - namedtype.OptionalNamedType('null', univ.Null('')), - namedtype.DefaultedNamedType('age', univ.Integer(34)) - )) - self.s2 = self.s1.clone() - def testTag(self): - assert self.s1.getTagSet() == tag.TagSet( - (), - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ), 'wrong tagSet' - def testByTypeWithPythonValue(self): - self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') - assert self.s1.getComponentByType( - univ.OctetString.tagSet - ) == str2octs('abc'), 'set by name fails' - def testByTypeWithInstance(self): - self.s1.setComponentByType(univ.OctetString.tagSet, univ.OctetString('abc')) - assert self.s1.getComponentByType( - univ.OctetString.tagSet - ) == str2octs('abc'), 'set by name fails' - def testGetTagMap(self): - assert self.s1.getTagMap().getPosMap() == { - univ.Set.tagSet: univ.Set() - } - def testGetComponentTagMap(self): - assert self.s1.getComponentTagMap().getPosMap() == { - univ.OctetString.tagSet: univ.OctetString(''), - univ.Null.tagSet: univ.Null(''), - univ.Integer.tagSet: univ.Integer(34) - } - def testGetPositionByType(self): - assert self.s1.getComponentPositionByType( - univ.Null().getTagSet() - ) == 1 - -class Choice(unittest.TestCase): - def setUp(self): - innerComp = univ.Choice(componentType=namedtype.NamedTypes( - namedtype.NamedType('count', univ.Integer()), - namedtype.NamedType('flag', univ.Boolean()) - )) - self.s1 = univ.Choice(componentType=namedtype.NamedTypes( - namedtype.NamedType('name', univ.OctetString()), - namedtype.NamedType('sex', innerComp) - )) - def testTag(self): - assert self.s1.getTagSet() == tag.TagSet(), 'wrong tagSet' - def testOuterByTypeWithPythonValue(self): - self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') - assert self.s1.getComponentByType( - univ.OctetString.tagSet - ) == str2octs('abc') - def testOuterByTypeWithInstanceValue(self): - self.s1.setComponentByType( - univ.OctetString.tagSet, univ.OctetString('abc') - ) - assert self.s1.getComponentByType( - univ.OctetString.tagSet - ) == str2octs('abc') - def testInnerByTypeWithPythonValue(self): - self.s1.setComponentByType(univ.Integer.tagSet, 123, 1) - assert self.s1.getComponentByType( - univ.Integer.tagSet, 1 - ) == 123 - def testInnerByTypeWithInstanceValue(self): - self.s1.setComponentByType( - univ.Integer.tagSet, univ.Integer(123), 1 - ) - assert self.s1.getComponentByType( - univ.Integer.tagSet, 1 - ) == 123 - def testCmp(self): - self.s1.setComponentByName('name', univ.OctetString('abc')) - assert self.s1 == str2octs('abc'), '__cmp__() fails' - def testGetComponent(self): - self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') - assert self.s1.getComponent() == str2octs('abc'), 'getComponent() fails' - def testGetName(self): - self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') - assert self.s1.getName() == 'name', 'getName() fails' - def testSetComponentByPosition(self): - self.s1.setComponentByPosition(0, univ.OctetString('Jim')) - assert self.s1 == str2octs('Jim') - def testClone(self): - self.s1.setComponentByPosition(0, univ.OctetString('abc')) - s = self.s1.clone() - assert len(s) == 0 - s = self.s1.clone(cloneValueFlag=1) - assert len(s) == 1 - assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0) - -if __name__ == '__main__': unittest.main() diff --git a/third_party/python/pyasn1/test/codec/__init__.py b/third_party/python/pyasn1/tests/__init__.py similarity index 100% rename from third_party/python/pyasn1/test/codec/__init__.py rename to third_party/python/pyasn1/tests/__init__.py diff --git a/third_party/python/pyasn1/tests/__main__.py b/third_party/python/pyasn1/tests/__main__.py new file mode 100644 index 000000000000..c5c152ab5f32 --- /dev/null +++ b/third_party/python/pyasn1/tests/__main__.py @@ -0,0 +1,22 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.test_debug.suite', + 'tests.type.__main__.suite', + 'tests.codec.__main__.suite', + 'tests.compat.__main__.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/base.py b/third_party/python/pyasn1/tests/base.py new file mode 100644 index 000000000000..6faef6ed3979 --- /dev/null +++ b/third_party/python/pyasn1/tests/base.py @@ -0,0 +1,22 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys +try: + import unittest2 as unittest +except ImportError: + import unittest + +from pyasn1 import debug + + +class BaseTestCase(unittest.TestCase): + + def setUp(self): + debug.setLogger(debug.Debug('all', printer=lambda *x: None)) + + def tearDown(self): + debug.setLogger(None) diff --git a/third_party/python/pyasn1/test/codec/ber/__init__.py b/third_party/python/pyasn1/tests/codec/__init__.py similarity index 100% rename from third_party/python/pyasn1/test/codec/ber/__init__.py rename to third_party/python/pyasn1/tests/codec/__init__.py diff --git a/third_party/python/pyasn1/tests/codec/__main__.py b/third_party/python/pyasn1/tests/codec/__main__.py new file mode 100644 index 000000000000..bcfd96f2d2f3 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/__main__.py @@ -0,0 +1,22 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.codec.ber.__main__.suite', + 'tests.codec.cer.__main__.suite', + 'tests.codec.der.__main__.suite', + 'tests.codec.native.__main__.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/test/codec/cer/__init__.py b/third_party/python/pyasn1/tests/codec/ber/__init__.py similarity index 100% rename from third_party/python/pyasn1/test/codec/cer/__init__.py rename to third_party/python/pyasn1/tests/codec/ber/__init__.py diff --git a/third_party/python/pyasn1/tests/codec/ber/__main__.py b/third_party/python/pyasn1/tests/codec/ber/__main__.py new file mode 100644 index 000000000000..2909628c3eb4 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/ber/__main__.py @@ -0,0 +1,20 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.codec.ber.test_encoder.suite', + 'tests.codec.ber.test_decoder.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/ber/test_decoder.py b/third_party/python/pyasn1/tests/codec/ber/test_decoder.py new file mode 100644 index 000000000000..5ec3a5f16116 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/ber/test_decoder.py @@ -0,0 +1,1294 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import tag, namedtype, univ, char +from pyasn1.codec.ber import decoder, eoo +from pyasn1.compat.octets import ints2octs, str2octs, null +from pyasn1.error import PyAsn1Error + + +class LargeTagDecoderTestCase(BaseTestCase): + def testLargeTag(self): + assert decoder.decode(ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))) == (1, null) + + def testLongTag(self): + assert decoder.decode(ints2octs((0x1f, 2, 1, 0)))[0].tagSet == univ.Integer.tagSet + + def testTagsEquivalence(self): + integer = univ.Integer(2).subtype(implicitTag=tag.Tag(tag.tagClassContext, 0, 0)) + assert decoder.decode(ints2octs((0x9f, 0x80, 0x00, 0x02, 0x01, 0x02)), asn1Spec=integer) == decoder.decode( + ints2octs((0x9f, 0x00, 0x02, 0x01, 0x02)), asn1Spec=integer) + + +class DecoderCacheTestCase(BaseTestCase): + def testCache(self): + assert decoder.decode(ints2octs((0x1f, 2, 1, 0))) == decoder.decode(ints2octs((0x1f, 2, 1, 0))) + + +class IntegerDecoderTestCase(BaseTestCase): + def testPosInt(self): + assert decoder.decode(ints2octs((2, 1, 12))) == (12, null) + + def testNegInt(self): + assert decoder.decode(ints2octs((2, 1, 244))) == (-12, null) + + def testZero(self): + assert decoder.decode(ints2octs((2, 0))) == (0, null) + + def testZeroLong(self): + assert decoder.decode(ints2octs((2, 1, 0))) == (0, null) + + def testMinusOne(self): + assert decoder.decode(ints2octs((2, 1, 255))) == (-1, null) + + def testPosLong(self): + assert decoder.decode( + ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255)) + ) == (0xffffffffffffffff, null) + + def testNegLong(self): + assert decoder.decode( + ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1)) + ) == (-0xffffffffffffffff, null) + + def testSpec(self): + try: + decoder.decode( + ints2octs((2, 1, 12)), asn1Spec=univ.Null() + ) == (12, null) + except PyAsn1Error: + pass + else: + assert 0, 'wrong asn1Spec worked out' + assert decoder.decode( + ints2octs((2, 1, 12)), asn1Spec=univ.Integer() + ) == (12, null) + + def testTagFormat(self): + try: + decoder.decode(ints2octs((34, 1, 12))) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + +class BooleanDecoderTestCase(BaseTestCase): + def testTrue(self): + assert decoder.decode(ints2octs((1, 1, 1))) == (1, null) + + def testTrueNeg(self): + assert decoder.decode(ints2octs((1, 1, 255))) == (1, null) + + def testExtraTrue(self): + assert decoder.decode(ints2octs((1, 1, 1, 0, 120, 50, 50))) == (1, ints2octs((0, 120, 50, 50))) + + def testFalse(self): + assert decoder.decode(ints2octs((1, 1, 0))) == (0, null) + + def testTagFormat(self): + try: + decoder.decode(ints2octs((33, 1, 1))) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + +class BitStringDecoderTestCase(BaseTestCase): + def testDefMode(self): + assert decoder.decode( + ints2octs((3, 3, 1, 169, 138)) + ) == ((1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1), null) + + def testIndefMode(self): + assert decoder.decode( + ints2octs((3, 3, 1, 169, 138)) + ) == ((1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1), null) + + def testDefModeChunked(self): + assert decoder.decode( + ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)) + ) == ((1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1), null) + + def testIndefModeChunked(self): + assert decoder.decode( + ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)) + ) == ((1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1), null) + + def testDefModeChunkedSubst(self): + assert decoder.decode( + ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)), + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((3, 2, 0, 169, 3, 2, 1, 138)), str2octs('')) + + def testIndefModeChunkedSubst(self): + assert decoder.decode( + ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)), + substrateFun=lambda a, b, c: (b, str2octs('')) + ) == (ints2octs((3, 2, 0, 169, 3, 2, 1, 138, 0, 0)), str2octs('')) + + def testTypeChecking(self): + try: + decoder.decode(ints2octs((35, 4, 2, 2, 42, 42))) + except PyAsn1Error: + pass + else: + assert 0, 'accepted mis-encoded bit-string constructed out of an integer' + + +class OctetStringDecoderTestCase(BaseTestCase): + def testDefMode(self): + assert decoder.decode( + ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + ) == (str2octs('Quick brown fox'), null) + + def testIndefMode(self): + assert decoder.decode( + ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0)) + ) == (str2octs('Quick brown fox'), null) + + def testDefModeChunked(self): + assert decoder.decode( + ints2octs( + (36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)) + ) == (str2octs('Quick brown fox'), null) + + def testIndefModeChunked(self): + assert decoder.decode( + ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, + 120, 0, 0)) + ) == (str2octs('Quick brown fox'), null) + + def testDefModeChunkedSubst(self): + assert decoder.decode( + ints2octs( + (36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)), + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)), str2octs('')) + + def testIndefModeChunkedSubst(self): + assert decoder.decode( + ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, + 120, 0, 0)), + substrateFun=lambda a, b, c: (b, str2octs('')) + ) == (ints2octs( + (4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0)), str2octs('')) + + +class ExpTaggedOctetStringDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.o = univ.OctetString( + 'Quick brown fox', + tagSet=univ.OctetString.tagSet.tagExplicitly( + tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 5) + )) + + def testDefMode(self): + o, r = decoder.decode( + ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + ) + assert not r + assert self.o == o + assert self.o.tagSet == o.tagSet + assert self.o.isSameTypeWith(o) + + def testIndefMode(self): + o, r = decoder.decode( + ints2octs((101, 128, 36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)) + ) + assert not r + assert self.o == o + assert self.o.tagSet == o.tagSet + assert self.o.isSameTypeWith(o) + + def testDefModeChunked(self): + o, r = decoder.decode( + ints2octs((101, 25, 36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120)) + ) + assert not r + assert self.o == o + assert self.o.tagSet == o.tagSet + assert self.o.isSameTypeWith(o) + + def testIndefModeChunked(self): + o, r = decoder.decode( + ints2octs((101, 128, 36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0, 0, 0)) + ) + assert not r + assert self.o == o + assert self.o.tagSet == o.tagSet + assert self.o.isSameTypeWith(o) + + def testDefModeSubst(self): + assert decoder.decode( + ints2octs((101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), str2octs('')) + + def testIndefModeSubst(self): + assert decoder.decode( + ints2octs(( + 101, 128, 36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, + 0, 0, 0)), + substrateFun=lambda a, b, c: (b, str2octs('')) + ) == (ints2octs( + (36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0, 0, 0)), str2octs('')) + + +class NullDecoderTestCase(BaseTestCase): + def testNull(self): + assert decoder.decode(ints2octs((5, 0))) == (null, null) + + def testTagFormat(self): + try: + decoder.decode(ints2octs((37, 0))) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + +# Useful analysis of OID encoding issues could be found here: +# http://www.viathinksoft.de/~daniel-marschall/asn.1/oid_facts.html +class ObjectIdentifierDecoderTestCase(BaseTestCase): + def testOne(self): + assert decoder.decode( + ints2octs((6, 6, 43, 6, 0, 191, 255, 126)) + ) == ((1, 3, 6, 0, 0xffffe), null) + + def testEdge1(self): + assert decoder.decode( + ints2octs((6, 1, 39)) + ) == ((0, 39), null) + + def testEdge2(self): + assert decoder.decode( + ints2octs((6, 1, 79)) + ) == ((1, 39), null) + + def testEdge3(self): + assert decoder.decode( + ints2octs((6, 1, 120)) + ) == ((2, 40), null) + + def testEdge4(self): + assert decoder.decode( + ints2octs((6, 5, 0x90, 0x80, 0x80, 0x80, 0x4F)) + ) == ((2, 0xffffffff), null) + + def testEdge5(self): + assert decoder.decode( + ints2octs((6, 1, 0x7F)) + ) == ((2, 47), null) + + def testEdge6(self): + assert decoder.decode( + ints2octs((6, 2, 0x81, 0x00)) + ) == ((2, 48), null) + + def testEdge7(self): + assert decoder.decode( + ints2octs((6, 3, 0x81, 0x34, 0x03)) + ) == ((2, 100, 3), null) + + def testEdge8(self): + assert decoder.decode( + ints2octs((6, 2, 133, 0)) + ) == ((2, 560), null) + + def testEdge9(self): + assert decoder.decode( + ints2octs((6, 4, 0x88, 0x84, 0x87, 0x02)) + ) == ((2, 16843570), null) + + def testNonLeading0x80(self): + assert decoder.decode( + ints2octs((6, 5, 85, 4, 129, 128, 0)), + ) == ((2, 5, 4, 16384), null) + + def testLeading0x80Case1(self): + try: + decoder.decode( + ints2octs((6, 5, 85, 4, 128, 129, 0)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'Leading 0x80 tolarated' + + def testLeading0x80Case2(self): + try: + decoder.decode( + ints2octs((6, 7, 1, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'Leading 0x80 tolarated' + + def testLeading0x80Case3(self): + try: + decoder.decode( + ints2octs((6, 2, 0x80, 1)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'Leading 0x80 tolarated' + + def testLeading0x80Case4(self): + try: + decoder.decode( + ints2octs((6, 2, 0x80, 0x7F)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'Leading 0x80 tolarated' + + def testTagFormat(self): + try: + decoder.decode(ints2octs((38, 1, 239))) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + def testZeroLength(self): + try: + decoder.decode(ints2octs((6, 0, 0))) + except PyAsn1Error: + pass + else: + assert 0, 'zero length tolarated' + + def testIndefiniteLength(self): + try: + decoder.decode(ints2octs((6, 128, 0))) + except PyAsn1Error: + pass + else: + assert 0, 'indefinite length tolarated' + + def testReservedLength(self): + try: + decoder.decode(ints2octs((6, 255, 0))) + except PyAsn1Error: + pass + else: + assert 0, 'reserved length tolerated' + + def testLarge1(self): + assert decoder.decode( + ints2octs((0x06, 0x11, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, + 0xE2, 0xB7, 0x17)) + ) == ((2, 18446744073709551535184467440737095), null) + + def testLarge2(self): + assert decoder.decode( + ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, + 0xB8, 0xCB, 0xE2, 0xB6, 0x47)) + ) == ((2, 999, 18446744073709551535184467440737095), null) + + +class RealDecoderTestCase(BaseTestCase): + def testChar(self): + assert decoder.decode( + ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49)) + ) == (univ.Real((123, 10, 11)), null) + + def testBin1(self): # check base = 2 + assert decoder.decode( # (0.5, 2, 0) encoded with base = 2 + ints2octs((9, 3, 128, 255, 1)) + ) == (univ.Real((1, 2, -1)), null) + + def testBin2(self): # check base = 2 and scale factor + assert decoder.decode( # (3.25, 2, 0) encoded with base = 8 + ints2octs((9, 3, 148, 255, 13)) + ) == (univ.Real((26, 2, -3)), null) + + def testBin3(self): # check base = 16 + assert decoder.decode( # (0.00390625, 2, 0) encoded with base = 16 + ints2octs((9, 3, 160, 254, 1)) + ) == (univ.Real((1, 2, -8)), null) + + def testBin4(self): # check exponenta = 0 + assert decoder.decode( # (1, 2, 0) encoded with base = 2 + ints2octs((9, 3, 128, 0, 1)) + ) == (univ.Real((1, 2, 0)), null) + + def testBin5(self): # case of 2 octs for exponenta and negative exponenta + assert decoder.decode( # (3, 2, -1020) encoded with base = 16 + ints2octs((9, 4, 161, 255, 1, 3)) + ) == (univ.Real((3, 2, -1020)), null) + +# TODO: this requires Real type comparison fix + +# def testBin6(self): +# assert decoder.decode( +# ints2octs((9, 5, 162, 0, 255, 255, 1)) +# ) == (univ.Real((1, 2, 262140)), null) + +# def testBin7(self): +# assert decoder.decode( +# ints2octs((9, 7, 227, 4, 1, 35, 69, 103, 1)) +# ) == (univ.Real((-1, 2, 76354972)), null) + + def testPlusInf(self): + assert decoder.decode( + ints2octs((9, 1, 64)) + ) == (univ.Real('inf'), null) + + def testMinusInf(self): + assert decoder.decode( + ints2octs((9, 1, 65)) + ) == (univ.Real('-inf'), null) + + def testEmpty(self): + assert decoder.decode( + ints2octs((9, 0)) + ) == (univ.Real(0.0), null) + + def testTagFormat(self): + try: + decoder.decode(ints2octs((41, 0))) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + def testShortEncoding(self): + try: + decoder.decode(ints2octs((9, 1, 131))) + except PyAsn1Error: + pass + else: + assert 0, 'accepted too-short real' + + +if sys.version_info[0:2] > (2, 5): + class UniversalStringDecoderTestCase(BaseTestCase): + def testDecoder(self): + assert decoder.decode(ints2octs((28, 12, 0, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99))) == (char.UniversalString(sys.version_info[0] == 3 and 'abc' or unicode('abc')), null) + + +class BMPStringDecoderTestCase(BaseTestCase): + def testDecoder(self): + assert decoder.decode(ints2octs((30, 6, 0, 97, 0, 98, 0, 99))) == (char.BMPString(sys.version_info[0] == 3 and 'abc' or unicode('abc')), null) + + +class UTF8StringDecoderTestCase(BaseTestCase): + def testDecoder(self): + assert decoder.decode(ints2octs((12, 3, 97, 98, 99))) == (char.UTF8String(sys.version_info[0] == 3 and 'abc' or unicode('abc')), null) + + +class SequenceOfDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.SequenceOf(componentType=univ.OctetString()) + self.s.setComponentByPosition(0, univ.OctetString('quick brown')) + + def testDefMode(self): + assert decoder.decode( + ints2octs((48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + ) == (self.s, null) + + def testIndefMode(self): + assert decoder.decode( + ints2octs((48, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + ) == (self.s, null) + + def testDefModeChunked(self): + assert decoder.decode( + ints2octs((48, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + ) == (self.s, null) + + def testIndefModeChunked(self): + assert decoder.decode( + ints2octs((48, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + ) == (self.s, null) + + def testSchemalessDecoder(self): + assert decoder.decode( + ints2octs((48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=univ.SequenceOf() + ) == (self.s, null) + + +class ExpTaggedSequenceOfDecoderTestCase(BaseTestCase): + + def testWithSchema(self): + s = univ.SequenceOf().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)) + s2, r = decoder.decode( + ints2octs((163, 15, 48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=s + ) + assert not r + assert s2 == [str2octs('quick brown')] + assert s.tagSet == s2.tagSet + + def testWithoutSchema(self): + s = univ.SequenceOf().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)) + s2, r = decoder.decode( + ints2octs((163, 15, 48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + ) + assert not r + assert s2 == [str2octs('quick brown')] + assert s.tagSet == s2.tagSet + + +class SequenceOfDecoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SequenceOf(componentType=univ.OctetString()) + self.s.setComponentByPosition(0, univ.OctetString('quick brown')) + + def testDefMode(self): + assert decoder.decode( + ints2octs((48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefMode(self): + assert decoder.decode( + ints2octs((48, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testDefModeChunked(self): + assert decoder.decode( + ints2octs((48, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefModeChunked(self): + assert decoder.decode( + ints2octs((48, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + +class SetOfDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SetOf(componentType=univ.OctetString()) + self.s.setComponentByPosition(0, univ.OctetString('quick brown')) + + def testDefMode(self): + assert decoder.decode( + ints2octs((49, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + ) == (self.s, null) + + def testIndefMode(self): + assert decoder.decode( + ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + ) == (self.s, null) + + def testDefModeChunked(self): + assert decoder.decode( + ints2octs((49, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + ) == (self.s, null) + + def testIndefModeChunked(self): + assert decoder.decode( + ints2octs((49, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + ) == (self.s, null) + + def testSchemalessDecoder(self): + assert decoder.decode( + ints2octs((49, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=univ.SetOf() + ) == (self.s, null) + + +class SetOfDecoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SetOf(componentType=univ.OctetString()) + self.s.setComponentByPosition(0, univ.OctetString('quick brown')) + + def testDefMode(self): + assert decoder.decode( + ints2octs((49, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefMode(self): + assert decoder.decode( + ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testDefModeChunked(self): + assert decoder.decode( + ints2octs((49, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefModeChunked(self): + assert decoder.decode( + ints2octs((49, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + +class SequenceDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null(null)), + namedtype.NamedType('first-name', univ.OctetString(null)), + namedtype.NamedType('age', univ.Integer(33)) + ) + ) + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testWithOptionalAndDefaultedDefMode(self): + assert decoder.decode( + ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefMode(self): + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeChunked(self): + assert decoder.decode( + ints2octs( + (48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefModeChunked(self): + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeSubst(self): + assert decoder.decode( + ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), str2octs('')) + + def testWithOptionalAndDefaultedIndefModeSubst(self): + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), + substrateFun=lambda a, b, c: (b, str2octs('')) + ) == (ints2octs( + (5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), str2octs('')) + + def testTagFormat(self): + try: + decoder.decode( + ints2octs((16, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + +class SequenceDecoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null(null)), + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + + def __initWithOptional(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + + def __initWithDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def __initWithOptionalAndDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testDefMode(self): + self.__init() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefMode(self): + self.__init() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testDefModeChunked(self): + self.__init() + assert decoder.decode( + ints2octs((48, 2, 5, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefModeChunked(self): + self.__init() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalDefMode(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((48, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionaIndefMode(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 0, 0)), + asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalDefModeChunked(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((48, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)), + asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalIndefModeChunked(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, + 0, 0, 0)), + asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedDefMode(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((48, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedIndefMode(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedDefModeChunked(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((48, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedIndefModeChunked(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefMode(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), + asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefMode(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, + 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs( + (48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)), + asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, + 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + +class SetDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null(null)), + namedtype.NamedType('first-name', univ.OctetString(null)), + namedtype.NamedType('age', univ.Integer(33)) + ) + ) + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testWithOptionalAndDefaultedDefMode(self): + assert decoder.decode( + ints2octs((49, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefMode(self): + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeChunked(self): + assert decoder.decode( + ints2octs( + (49, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefModeChunked(self): + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeSubst(self): + assert decoder.decode( + ints2octs((49, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), str2octs('')) + + def testWithOptionalAndDefaultedIndefModeSubst(self): + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), + substrateFun=lambda a, b, c: (b, str2octs('')) + ) == (ints2octs( + (5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), str2octs('')) + + def testTagFormat(self): + try: + decoder.decode( + ints2octs((16, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'wrong tagFormat worked out' + + +class SetDecoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null(null)), + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + + def __initWithOptional(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + + def __initWithDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def __initWithOptionalAndDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testDefMode(self): + self.__init() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefMode(self): + self.__init() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testDefModeChunked(self): + self.__init() + assert decoder.decode( + ints2octs((49, 2, 5, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testIndefModeChunked(self): + self.__init() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalDefMode(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((49, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionaIndefMode(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalDefModeChunked(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((49, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalIndefModeChunked(self): + self.__initWithOptional() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedDefMode(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((49, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedIndefMode(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedDefModeChunked(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((49, 5, 5, 0, 2, 1, 1)), asn1Spec=self.s + ) == (self.s, null) + + def testWithDefaultedIndefModeChunked(self): + self.__initWithDefaulted() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefMode(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((49, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeReordered(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((49, 18, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefMode(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefModeReordered(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((49, 128, 2, 1, 1, 5, 0, 36, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedDefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((49, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)), asn1Spec=self.s + ) == (self.s, null) + + def testWithOptionalAndDefaultedIndefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert decoder.decode( + ints2octs((49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)), asn1Spec=self.s + ) == (self.s, null) + + +class SequenceOfWithExpTaggedOctetStringDecoder(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SequenceOf( + componentType=univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)) + ) + self.s.setComponentByPosition(0, 'q') + self.s2 = univ.SequenceOf() + + def testDefModeSchema(self): + s, r = decoder.decode(ints2octs((48, 5, 163, 3, 4, 1, 113)), asn1Spec=self.s) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testIndefModeSchema(self): + s, r = decoder.decode(ints2octs((48, 128, 163, 128, 4, 1, 113, 0, 0, 0, 0)), asn1Spec=self.s) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testDefModeNoComponent(self): + s, r = decoder.decode(ints2octs((48, 5, 163, 3, 4, 1, 113)), asn1Spec=self.s2) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testIndefModeNoComponent(self): + s, r = decoder.decode(ints2octs((48, 128, 163, 128, 4, 1, 113, 0, 0, 0, 0)), asn1Spec=self.s2) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testDefModeSchemaless(self): + s, r = decoder.decode(ints2octs((48, 5, 163, 3, 4, 1, 113))) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testIndefModeSchemaless(self): + s, r = decoder.decode(ints2octs((48, 128, 163, 128, 4, 1, 113, 0, 0, 0, 0))) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + +class SequenceWithExpTaggedOctetStringDecoder(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType( + 'x', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)) + ) + ) + ) + self.s.setComponentByPosition(0, 'q') + self.s2 = univ.Sequence() + + def testDefModeSchema(self): + s, r = decoder.decode(ints2octs((48, 5, 163, 3, 4, 1, 113)), asn1Spec=self.s) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testIndefModeSchema(self): + s, r = decoder.decode(ints2octs((48, 128, 163, 128, 4, 1, 113, 0, 0, 0, 0)), asn1Spec=self.s) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testDefModeNoComponent(self): + s, r = decoder.decode(ints2octs((48, 5, 163, 3, 4, 1, 113)), asn1Spec=self.s2) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testIndefModeNoComponent(self): + s, r = decoder.decode(ints2octs((48, 128, 163, 128, 4, 1, 113, 0, 0, 0, 0)), asn1Spec=self.s2) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testDefModeSchemaless(self): + s, r = decoder.decode(ints2octs((48, 5, 163, 3, 4, 1, 113))) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + def testIndefModeSchemaless(self): + s, r = decoder.decode(ints2octs((48, 128, 163, 128, 4, 1, 113, 0, 0, 0, 0))) + assert not r + assert s == self.s + assert s.tagSet == self.s.tagSet + + +class ChoiceDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null(null)), + namedtype.NamedType('number', univ.Integer(0)), + namedtype.NamedType('string', univ.OctetString()) + ) + ) + + def testBySpec(self): + self.s.setComponentByPosition(0, univ.Null(null)) + assert decoder.decode( + ints2octs((5, 0)), asn1Spec=self.s + ) == (self.s, null) + + def testWithoutSpec(self): + self.s.setComponentByPosition(0, univ.Null(null)) + assert decoder.decode(ints2octs((5, 0))) == (self.s, null) + assert decoder.decode(ints2octs((5, 0))) == (univ.Null(null), null) + + def testUndefLength(self): + self.s.setComponentByPosition(2, univ.OctetString('abcdefgh')) + assert decoder.decode(ints2octs((36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0)), + asn1Spec=self.s) == (self.s, null) + + def testExplicitTag(self): + s = self.s.subtype(explicitTag=tag.Tag(tag.tagClassContext, + tag.tagFormatConstructed, 4)) + s.setComponentByPosition(0, univ.Null(null)) + assert decoder.decode(ints2octs((164, 2, 5, 0)), asn1Spec=s) == (s, null) + + def testExplicitTagUndefLength(self): + s = self.s.subtype(explicitTag=tag.Tag(tag.tagClassContext, + tag.tagFormatConstructed, 4)) + s.setComponentByPosition(0, univ.Null(null)) + assert decoder.decode(ints2octs((164, 128, 5, 0, 0, 0)), asn1Spec=s) == (s, null) + + +class AnyDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Any() + + def testByUntagged(self): + assert decoder.decode( + ints2octs((4, 3, 102, 111, 120)), asn1Spec=self.s + ) == (univ.Any('\004\003fox'), null) + + def testTaggedEx(self): + s = univ.Any('\004\003fox').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) + assert decoder.decode(ints2octs((164, 5, 4, 3, 102, 111, 120)), asn1Spec=s) == (s, null) + + def testTaggedIm(self): + s = univ.Any('\004\003fox').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) + assert decoder.decode(ints2octs((132, 5, 4, 3, 102, 111, 120)), asn1Spec=s) == (s, null) + + def testByUntaggedIndefMode(self): + assert decoder.decode( + ints2octs((4, 3, 102, 111, 120)), asn1Spec=self.s + ) == (univ.Any('\004\003fox'), null) + + def testTaggedExIndefMode(self): + s = univ.Any('\004\003fox').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) + assert decoder.decode(ints2octs((164, 128, 4, 3, 102, 111, 120, 0, 0)), asn1Spec=s) == (s, null) + + def testTaggedImIndefMode(self): + s = univ.Any('\004\003fox').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)) + assert decoder.decode(ints2octs((164, 128, 4, 3, 102, 111, 120, 0, 0)), asn1Spec=s) == (s, null) + + def testByUntaggedSubst(self): + assert decoder.decode( + ints2octs((4, 3, 102, 111, 120)), + asn1Spec=self.s, + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((4, 3, 102, 111, 120)), str2octs('')) + + def testTaggedExSubst(self): + assert decoder.decode( + ints2octs((164, 5, 4, 3, 102, 111, 120)), + asn1Spec=self.s, + substrateFun=lambda a, b, c: (b, b[c:]) + ) == (ints2octs((164, 5, 4, 3, 102, 111, 120)), str2octs('')) + + +class EndOfOctetsTestCase(BaseTestCase): + def testUnexpectedEoo(self): + try: + decoder.decode(ints2octs((0, 0))) + except PyAsn1Error: + pass + else: + assert 0, 'end-of-contents octets accepted at top level' + + def testExpectedEoo(self): + result, remainder = decoder.decode(ints2octs((0, 0)), allowEoo=True) + assert eoo.endOfOctets.isSameTypeWith(result) and result == eoo.endOfOctets and result is eoo.endOfOctets + assert remainder == null + + def testDefiniteNoEoo(self): + try: + decoder.decode(ints2octs((0x23, 0x02, 0x00, 0x00))) + except PyAsn1Error: + pass + else: + assert 0, 'end-of-contents octets accepted inside definite-length encoding' + + def testIndefiniteEoo(self): + result, remainder = decoder.decode(ints2octs((0x23, 0x80, 0x00, 0x00))) + assert result == () and remainder == null, 'incorrect decoding of indefinite length end-of-octets' + + def testNoLongFormEoo(self): + try: + decoder.decode(ints2octs((0x23, 0x80, 0x00, 0x81, 0x00))) + except PyAsn1Error: + pass + else: + assert 0, 'end-of-contents octets accepted with invalid long-form length' + + def testNoConstructedEoo(self): + try: + decoder.decode(ints2octs((0x23, 0x80, 0x20, 0x00))) + except PyAsn1Error: + pass + else: + assert 0, 'end-of-contents octets accepted with invalid constructed encoding' + + def testNoEooData(self): + try: + decoder.decode(ints2octs((0x23, 0x80, 0x00, 0x01, 0x00))) + except PyAsn1Error: + pass + else: + assert 0, 'end-of-contents octets accepted with unexpected data' + + +class NonStringDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null(null)), + namedtype.NamedType('first-name', univ.OctetString(null)), + namedtype.NamedType('age', univ.Integer(33)) + ) + ) + self.s.setComponentByPosition(0, univ.Null(null)) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + self.substrate = ints2octs([48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1]) + + def testOctetString(self): + s, _ = decoder.decode(univ.OctetString(self.substrate), asn1Spec=self.s) + assert self.s == s + + def testAny(self): + s, _ = decoder.decode(univ.Any(self.substrate), asn1Spec=self.s) + assert self.s == s + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/ber/test_encoder.py b/third_party/python/pyasn1/tests/codec/ber/test_encoder.py new file mode 100644 index 000000000000..09a7572676b3 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/ber/test_encoder.py @@ -0,0 +1,940 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import tag, namedtype, univ, char +from pyasn1.codec.ber import encoder +from pyasn1.compat.octets import ints2octs +from pyasn1.error import PyAsn1Error + + +class LargeTagEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.o = univ.Integer().subtype( + value=1, explicitTag=tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0xdeadbeaf) + ) + + def testEncoder(self): + assert encoder.encode(self.o) == ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1)) + + +class IntegerEncoderTestCase(BaseTestCase): + def testPosInt(self): + assert encoder.encode(univ.Integer(12)) == ints2octs((2, 1, 12)) + + def testNegInt(self): + assert encoder.encode(univ.Integer(-12)) == ints2octs((2, 1, 244)) + + def testZero(self): + assert encoder.encode(univ.Integer(0)) == ints2octs((2, 1, 0)) + + def testCompactZero(self): + encoder.IntegerEncoder.supportCompactZero = True + substrate = encoder.encode(univ.Integer(0)) + encoder.IntegerEncoder.supportCompactZero = False + assert substrate == ints2octs((2, 0)) + + def testMinusOne(self): + assert encoder.encode(univ.Integer(-1)) == ints2octs((2, 1, 255)) + + def testPosLong(self): + assert encoder.encode( + univ.Integer(0xffffffffffffffff) + ) == ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255)) + + def testNegLong(self): + assert encoder.encode( + univ.Integer(-0xffffffffffffffff) + ) == ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1)) + + +class BooleanEncoderTestCase(BaseTestCase): + def testTrue(self): + assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 1)) + + def testFalse(self): + assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0)) + + +class BitStringEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.b = univ.BitString((1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1)) + + def testDefMode(self): + assert encoder.encode(self.b) == ints2octs((3, 3, 1, 169, 138)) + + def testIndefMode(self): + assert encoder.encode( + self.b, defMode=False + ) == ints2octs((3, 3, 1, 169, 138)) + + def testDefModeChunked(self): + assert encoder.encode( + self.b, maxChunkSize=1 + ) == ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)) + + def testIndefModeChunked(self): + assert encoder.encode( + self.b, defMode=False, maxChunkSize=1 + ) == ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)) + + def testEmptyValue(self): + assert encoder.encode(univ.BitString([])) == ints2octs((3, 1, 0)) + + +class OctetStringEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.o = univ.OctetString('Quick brown fox') + + def testDefMode(self): + assert encoder.encode(self.o) == ints2octs( + (4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + + def testIndefMode(self): + assert encoder.encode( + self.o, defMode=False + ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + + def testDefModeChunked(self): + assert encoder.encode( + self.o, maxChunkSize=4 + ) == ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, + 110, 32, 4, 3, 102, 111, 120)) + + def testIndefModeChunked(self): + assert encoder.encode( + self.o, defMode=False, maxChunkSize=4 + ) == ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, + 32, 4, 3, 102, 111, 120, 0, 0)) + + +class ExpTaggedOctetStringEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.o = univ.OctetString().subtype( + value='Quick brown fox', + explicitTag=tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 5) + ) + + def testDefMode(self): + assert encoder.encode(self.o) == ints2octs( + (101, 17, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + + def testIndefMode(self): + assert encoder.encode( + self.o, defMode=False + ) == ints2octs((101, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0)) + + def testDefModeChunked(self): + assert encoder.encode( + self.o, defMode=True, maxChunkSize=4 + ) == ints2octs((101, 25, 36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, + 102, 111, 120)) + + def testIndefModeChunked(self): + assert encoder.encode( + self.o, defMode=False, maxChunkSize=4 + ) == ints2octs((101, 128, 36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0, 0, 0)) + + +class NullEncoderTestCase(BaseTestCase): + def testNull(self): + assert encoder.encode(univ.Null('')) == ints2octs((5, 0)) + + +class ObjectIdentifierEncoderTestCase(BaseTestCase): + def testOne(self): + assert encoder.encode( + univ.ObjectIdentifier((1, 3, 6, 0, 0xffffe)) + ) == ints2octs((6, 6, 43, 6, 0, 191, 255, 126)) + + def testEdge1(self): + assert encoder.encode( + univ.ObjectIdentifier((0, 39)) + ) == ints2octs((6, 1, 39)) + + def testEdge2(self): + assert encoder.encode( + univ.ObjectIdentifier((1, 39)) + ) == ints2octs((6, 1, 79)) + + def testEdge3(self): + # 01111111 + assert encoder.encode( + univ.ObjectIdentifier((2, 40)) + ) == ints2octs((6, 1, 120)) + + def testEdge4(self): + # 10010000|10000000|10000000|10000000|01001111 + assert encoder.encode( + univ.ObjectIdentifier((2, 0xffffffff)) + ) == ints2octs((6, 5, 0x90, 0x80, 0x80, 0x80, 0x4F)) + + def testEdge5(self): + # 01111111 + assert encoder.encode( + univ.ObjectIdentifier((2, 47)) + ) == ints2octs((6, 1, 0x7F)) + + def testEdge6(self): + # 10000001|00000000 + assert encoder.encode( + univ.ObjectIdentifier((2, 48)) + ) == ints2octs((6, 2, 0x81, 0x00)) + + def testEdge7(self): + # 10000001|00110100|00000003 + assert encoder.encode( + univ.ObjectIdentifier((2, 100, 3)) + ) == ints2octs((6, 3, 0x81, 0x34, 0x03)) + + def testEdge8(self): + # 10000101|00000000 + assert encoder.encode( + univ.ObjectIdentifier((2, 560)) + ) == ints2octs((6, 2, 133, 0)) + + def testEdge9(self): + # 10001000|10000100|10000111|0000010 + assert encoder.encode( + univ.ObjectIdentifier((2, 16843570)) + ) == ints2octs((6, 4, 0x88, 0x84, 0x87, 0x02)) + + def testEdgeA(self): + assert encoder.encode( + univ.ObjectIdentifier((2, 5)) + ) == ints2octs((6, 1, 85)) + + def testImpossible1(self): + try: + encoder.encode(univ.ObjectIdentifier((3, 1, 2))) + except PyAsn1Error: + pass + else: + assert 0, 'impossible leading arc tolerated' + + def testImpossible2(self): + try: + encoder.encode(univ.ObjectIdentifier((0,))) + except PyAsn1Error: + pass + else: + assert 0, 'single arc OID tolerated' + + def testImpossible3(self): + try: + encoder.encode(univ.ObjectIdentifier((0, 40))) + except PyAsn1Error: + pass + else: + assert 0, 'second arc overflow tolerated' + + def testImpossible4(self): + try: + encoder.encode(univ.ObjectIdentifier((1, 40))) + except PyAsn1Error: + pass + else: + assert 0, 'second arc overflow tolerated' + + def testLarge1(self): + assert encoder.encode( + univ.ObjectIdentifier((2, 18446744073709551535184467440737095)) + ) == ints2octs((0x06, 0x11, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, + 0xE2, 0xB7, 0x17)) + + def testLarge2(self): + assert encoder.encode( + univ.ObjectIdentifier((2, 999, 18446744073709551535184467440737095)) + ) == ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, + 0xB8, 0xCB, 0xE2, 0xB6, 0x47)) + + +class RealEncoderTestCase(BaseTestCase): + def testChar(self): + assert encoder.encode( + univ.Real((123, 10, 11)) + ) == ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49)) + + def testBin1(self): + assert encoder.encode( # default binEncBase = 2 + univ.Real((0.5, 2, 0)) # check encbase = 2 and exponent = -1 + ) == ints2octs((9, 3, 128, 255, 1)) + + def testBin2(self): + r = univ.Real((3.25, 2, 0)) + r.binEncBase = 8 # change binEncBase only for this instance of Real + assert encoder.encode( + r # check encbase = 8 + ) == ints2octs((9, 3, 148, 255, 13)) + + def testBin3(self): + # change binEncBase in the RealEncoder instance => for all further Real + binEncBase, encoder.typeMap[univ.Real.typeId].binEncBase = encoder.typeMap[univ.Real.typeId].binEncBase, 16 + assert encoder.encode( + univ.Real((0.00390625, 2, 0)) # check encbase = 16 + ) == ints2octs((9, 3, 160, 254, 1)) + encoder.typeMap[univ.Real.typeId].binEncBase = binEncBase + + def testBin4(self): + # choose binEncBase automatically for all further Real (testBin[4-7]) + binEncBase, encoder.typeMap[univ.Real.typeId].binEncBase = encoder.typeMap[univ.Real.typeId].binEncBase, None + assert encoder.encode( + univ.Real((1, 2, 0)) # check exponenta = 0 + ) == ints2octs((9, 3, 128, 0, 1)) + encoder.typeMap[univ.Real.typeId].binEncBase = binEncBase + + def testBin5(self): + assert encoder.encode( + univ.Real((3, 2, -1020)) # case of 2 octs for exponent and + # negative exponenta and abs(exponent) is + # all 1's and fills the whole octet(s) + ) == ints2octs((9, 4, 129, 252, 4, 3)) + + def testBin6(self): + assert encoder.encode( + univ.Real((1, 2, 262140)) # case of 3 octs for exponent and + # check that first 9 bits for exponent + # are not all 1's + ) == ints2octs((9, 5, 130, 3, 255, 252, 1)) + + def testBin7(self): + assert encoder.encode( + univ.Real((-1, 2, 76354972)) # case of >3 octs for exponent and + # mantissa < 0 + ) == ints2octs((9, 7, 195, 4, 4, 141, 21, 156, 1)) + + def testPlusInf(self): + assert encoder.encode(univ.Real('inf')) == ints2octs((9, 1, 64)) + + def testMinusInf(self): + assert encoder.encode(univ.Real('-inf')) == ints2octs((9, 1, 65)) + + def testZero(self): + assert encoder.encode(univ.Real(0)) == ints2octs((9, 0)) + + +if sys.version_info[0:2] > (2, 5): + class UniversalStringEncoderTestCase(BaseTestCase): + def testEncoding(self): + assert encoder.encode(char.UniversalString(sys.version_info[0] == 3 and 'abc' or unicode('abc'))) == ints2octs( + (28, 12, 0, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99)), 'Incorrect encoding' + + +class BMPStringEncoderTestCase(BaseTestCase): + def testEncoding(self): + assert encoder.encode(char.BMPString(sys.version_info[0] == 3 and 'abc' or unicode('abc'))) == ints2octs( + (30, 6, 0, 97, 0, 98, 0, 99)), 'Incorrect encoding' + + +class UTF8StringEncoderTestCase(BaseTestCase): + def testEncoding(self): + assert encoder.encode(char.UTF8String(sys.version_info[0] == 3 and 'abc' or unicode('abc'))) == ints2octs( + (12, 3, 97, 98, 99)), 'Incorrect encoding' + + +class SequenceOfEncoderTestCase(BaseTestCase): + def testEmpty(self): + s = univ.SequenceOf() + assert encoder.encode(s) == ints2octs((48, 0)) + + def testDefMode(self): + s = univ.SequenceOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode(s) == ints2octs((48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testIndefMode(self): + s = univ.SequenceOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=False + ) == ints2octs((48, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testDefModeChunked(self): + s = univ.SequenceOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=True, maxChunkSize=4 + ) == ints2octs((48, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testIndefModeChunked(self): + s = univ.SequenceOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=False, maxChunkSize=4 + ) == ints2octs((48, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + + +class SequenceOfEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SequenceOf(componentType=univ.OctetString()) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0, 'quick brown') + + def testDefMode(self): + self.__init() + assert encoder.encode(self.s) == ints2octs((48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testIndefMode(self): + self.__init() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testDefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((48, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testIndefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((48, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + + +class SetOfEncoderTestCase(BaseTestCase): + def testEmpty(self): + s = univ.SetOf() + assert encoder.encode(s) == ints2octs((49, 0)) + + def testDefMode(self): + s = univ.SetOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode(s) == ints2octs((49, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testIndefMode(self): + s = univ.SetOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=False + ) == ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testDefModeChunked(self): + s = univ.SetOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=True, maxChunkSize=4 + ) == ints2octs((49, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testIndefModeChunked(self): + s = univ.SetOf() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=False, maxChunkSize=4 + ) == ints2octs((49, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + + +class SetOfEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SetOf(componentType=univ.OctetString()) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0, 'quick brown') + + def testDefMode(self): + self.__init() + assert encoder.encode(self.s) == ints2octs((49, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testIndefMode(self): + self.__init() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testDefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((49, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testIndefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((49, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + + +class SequenceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testDefMode(self): + assert encoder.encode(self.s) == ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + + def testIndefMode(self): + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testDefModeChunked(self): + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) + + def testIndefModeChunked(self): + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + + +class SequenceEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null()), + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0) + + def __initWithOptional(self): + self.s.clear() + self.s.setComponentByPosition(0) + self.s.setComponentByPosition(1, 'quick brown') + + def __initWithDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, '') + self.s.setComponentByPosition(2, 1) + + def __initWithOptionalAndDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testDefMode(self): + self.__init() + assert encoder.encode(self.s) == ints2octs((48, 2, 5, 0)) + + def testIndefMode(self): + self.__init() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 5, 0, 0, 0)) + + def testDefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((48, 2, 5, 0)) + + def testIndefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((48, 128, 5, 0, 0, 0)) + + def testWithOptionalDefMode(self): + self.__initWithOptional() + assert encoder.encode(self.s) == ints2octs( + (48, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testWithOptionalIndefMode(self): + self.__initWithOptional() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testWithOptionalDefModeChunked(self): + self.__initWithOptional() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((48, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testWithOptionalIndefModeChunked(self): + self.__initWithOptional() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs( + (48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + + def testWithDefaultedDefMode(self): + self.__initWithDefaulted() + assert encoder.encode(self.s) == ints2octs((48, 5, 5, 0, 2, 1, 1)) + + def testWithDefaultedIndefMode(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)) + + def testWithDefaultedDefModeChunked(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((48, 5, 5, 0, 2, 1, 1)) + + def testWithDefaultedIndefModeChunked(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)) + + def testWithOptionalAndDefaultedDefMode(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode(self.s) == ints2octs( + (48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + + def testWithOptionalAndDefaultedIndefMode(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testWithOptionalAndDefaultedDefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs( + (48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) + + def testWithOptionalAndDefaultedIndefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, + 0, 2, 1, 1, 0, 0)) + + +class ExpTaggedSequenceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('number', univ.Integer()), + ) + ) + + s = s.subtype( + explicitTag=tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 5) + ) + + s[0] = 12 + + self.s = s + + def testDefMode(self): + assert encoder.encode(self.s) == ints2octs((101, 5, 48, 3, 2, 1, 12)) + + def testIndefMode(self): + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((101, 128, 48, 128, 2, 1, 12, 0, 0, 0, 0)) + + +class ExpTaggedSequenceComponentEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('number', univ.Boolean().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), + ) + ) + + self.s[0] = True + + def testDefMode(self): + assert encoder.encode(self.s) == ints2octs((48, 5, 160, 3, 1, 1, 1)) + + def testIndefMode(self): + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((48, 128, 160, 3, 1, 1, 1, 0, 0, 0, 0)) + + +class SetEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testDefMode(self): + assert encoder.encode(self.s) == ints2octs((49, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + + def testIndefMode(self): + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((49, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testDefModeChunked(self): + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((49, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) + + def testIndefModeChunked(self): + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + + +class SetEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null()), + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0) + + def __initWithOptional(self): + self.s.clear() + self.s.setComponentByPosition(0) + self.s.setComponentByPosition(1, 'quick brown') + + def __initWithDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, '') + self.s.setComponentByPosition(2, 1) + + def __initWithOptionalAndDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testDefMode(self): + self.__init() + assert encoder.encode(self.s) == ints2octs((49, 2, 5, 0)) + + def testIndefMode(self): + self.__init() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((49, 128, 5, 0, 0, 0)) + + def testDefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((49, 2, 5, 0)) + + def testIndefModeChunked(self): + self.__init() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((49, 128, 5, 0, 0, 0)) + + def testWithOptionalDefMode(self): + self.__initWithOptional() + assert encoder.encode(self.s) == ints2octs( + (49, 15, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testWithOptionalIndefMode(self): + self.__initWithOptional() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((49, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testWithOptionalDefModeChunked(self): + self.__initWithOptional() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((49, 21, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testWithOptionalIndefModeChunked(self): + self.__initWithOptional() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs( + (49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0)) + + def testWithDefaultedDefMode(self): + self.__initWithDefaulted() + assert encoder.encode(self.s) == ints2octs((49, 5, 5, 0, 2, 1, 1)) + + def testWithDefaultedIndefMode(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((49, 128, 5, 0, 2, 1, 1, 0, 0)) + + def testWithDefaultedDefModeChunked(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs((49, 5, 5, 0, 2, 1, 1)) + + def testWithDefaultedIndefModeChunked(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((49, 128, 5, 0, 2, 1, 1, 0, 0)) + + def testWithOptionalAndDefaultedDefMode(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode(self.s) == ints2octs( + (49, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1)) + + def testWithOptionalAndDefaultedIndefMode(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s, defMode=False + ) == ints2octs((49, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testWithOptionalAndDefaultedDefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s, defMode=True, maxChunkSize=4 + ) == ints2octs( + (49, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1)) + + def testWithOptionalAndDefaultedIndefModeChunked(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s, defMode=False, maxChunkSize=4 + ) == ints2octs((49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0)) + + +class ChoiceEncoderTestCase(BaseTestCase): + + def testEmpty(self): + s = univ.Choice() + try: + encoder.encode(s) + except PyAsn1Error: + pass + else: + assert 0, 'encoded unset choice' + + def testDefModeOptionOne(self): + s = univ.Choice() + s.setComponentByPosition(0, univ.Null('')) + assert encoder.encode(s) == ints2octs((5, 0)) + + def testDefModeOptionTwo(self): + s = univ.Choice() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode(s) == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testIndefMode(self): + s = univ.Choice() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=False + ) == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)) + + def testDefModeChunked(self): + s = univ.Choice() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=True, maxChunkSize=4 + ) == ints2octs((36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110)) + + def testIndefModeChunked(self): + s = univ.Choice() + s.setComponentByPosition(0, univ.OctetString('quick brown')) + assert encoder.encode( + s, defMode=False, maxChunkSize=4 + ) == ints2octs((36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0)) + + +class ChoiceEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null('')), + namedtype.NamedType('number', univ.Integer(0)), + namedtype.NamedType('string', univ.OctetString()) + ) + ) + + def testEmpty(self): + try: + encoder.encode(self.s) + except PyAsn1Error: + pass + else: + assert 0, 'encoded unset choice' + + def testFilled(self): + self.s.setComponentByPosition(0, univ.Null('')) + assert encoder.encode(self.s) == ints2octs((5, 0)) + + def testTagged(self): + s = self.s.subtype( + explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4) + ) + s.setComponentByPosition(0, univ.Null('')) + assert encoder.encode(s) == ints2octs((164, 2, 5, 0)) + + def testUndefLength(self): + self.s.setComponentByPosition(2, univ.OctetString('abcdefgh')) + assert encoder.encode(self.s, defMode=False, maxChunkSize=3) == ints2octs( + (36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0)) + + def testTaggedUndefLength(self): + s = self.s.subtype( + explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4) + ) + s.setComponentByPosition(2, univ.OctetString('abcdefgh')) + assert encoder.encode(s, defMode=False, maxChunkSize=3) == ints2octs( + (164, 128, 36, 128, 4, 3, 97, 98, 99, 4, 3, 100, 101, 102, 4, 2, 103, 104, 0, 0, 0, 0)) + + +class AnyEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Any(encoder.encode(univ.OctetString('fox'))) + + def testUntagged(self): + assert encoder.encode(self.s) == ints2octs((4, 3, 102, 111, 120)) + + def testTaggedEx(self): + s = self.s.subtype( + explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4) + ) + assert encoder.encode(s) == ints2octs((164, 5, 4, 3, 102, 111, 120)) + + def testTaggedIm(self): + s = self.s.subtype( + implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4) + ) + assert encoder.encode(s) == ints2octs((132, 5, 4, 3, 102, 111, 120)) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/test/codec/der/__init__.py b/third_party/python/pyasn1/tests/codec/cer/__init__.py similarity index 100% rename from third_party/python/pyasn1/test/codec/der/__init__.py rename to third_party/python/pyasn1/tests/codec/cer/__init__.py diff --git a/third_party/python/pyasn1/tests/codec/cer/__main__.py b/third_party/python/pyasn1/tests/codec/cer/__main__.py new file mode 100644 index 000000000000..f641b8201b11 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/cer/__main__.py @@ -0,0 +1,20 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.codec.cer.test_encoder.suite', + 'tests.codec.cer.test_decoder.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/cer/test_decoder.py b/third_party/python/pyasn1/tests/codec/cer/test_decoder.py new file mode 100644 index 000000000000..828c17f1f807 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/cer/test_decoder.py @@ -0,0 +1,71 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.codec.cer import decoder +from pyasn1.compat.octets import ints2octs, str2octs, null +from pyasn1.error import PyAsn1Error + + +class BooleanDecoderTestCase(BaseTestCase): + def testTrue(self): + assert decoder.decode(ints2octs((1, 1, 255))) == (1, null) + + def testFalse(self): + assert decoder.decode(ints2octs((1, 1, 0))) == (0, null) + + def testEmpty(self): + try: + decoder.decode(ints2octs((1, 0))) + except PyAsn1Error: + pass + + def testOverflow(self): + try: + decoder.decode(ints2octs((1, 2, 0, 0))) + except PyAsn1Error: + pass + +class BitStringDecoderTestCase(BaseTestCase): + def testShortMode(self): + assert decoder.decode( + ints2octs((3, 3, 6, 170, 128)) + ) == (((1, 0) * 5), null) + + def testLongMode(self): + assert decoder.decode( + ints2octs((3, 127, 6) + (170,) * 125 + (128,)) + ) == (((1, 0) * 501), null) + + # TODO: test failures on short chunked and long unchunked substrate samples + + +class OctetStringDecoderTestCase(BaseTestCase): + def testShortMode(self): + assert decoder.decode( + ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)), + ) == (str2octs('Quick brown fox'), null) + + def testLongMode(self): + assert decoder.decode( + ints2octs((36, 128, 4, 130, 3, 232) + (81,) * 1000 + (4, 1, 81, 0, 0)) + ) == (str2octs('Q' * 1001), null) + + # TODO: test failures on short chunked and long unchunked substrate samples + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/cer/test_encoder.py b/third_party/python/pyasn1/tests/codec/cer/test_encoder.py new file mode 100644 index 000000000000..32d87b0ba44d --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/cer/test_encoder.py @@ -0,0 +1,677 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import namedtype, univ, useful +from pyasn1.codec.cer import encoder +from pyasn1.compat.octets import ints2octs +from pyasn1.error import PyAsn1Error + + +class BooleanEncoderTestCase(BaseTestCase): + def testTrue(self): + assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 255)) + + def testFalse(self): + assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0)) + + +class BitStringEncoderTestCase(BaseTestCase): + def testShortMode(self): + assert encoder.encode( + univ.BitString((1, 0) * 5) + ) == ints2octs((3, 3, 6, 170, 128)) + + def testLongMode(self): + assert encoder.encode(univ.BitString((1, 0) * 501)) == ints2octs((3, 127, 6) + (170,) * 125 + (128,)) + + +class OctetStringEncoderTestCase(BaseTestCase): + def testShortMode(self): + assert encoder.encode( + univ.OctetString('Quick brown fox') + ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + + def testLongMode(self): + assert encoder.encode( + univ.OctetString('Q' * 1001) + ) == ints2octs((36, 128, 4, 130, 3, 232) + (81,) * 1000 + (4, 1, 81, 0, 0)) + + +class GeneralizedTimeEncoderTestCase(BaseTestCase): + # def testExtraZeroInSeconds(self): + # try: + # assert encoder.encode( + # useful.GeneralizedTime('20150501120112.10Z') + # ) + # except PyAsn1Error: + # pass + # else: + # assert 0, 'Meaningless trailing zero in fraction part tolerated' + + def testLocalTimezone(self): + try: + assert encoder.encode( + useful.GeneralizedTime('20150501120112.1+0200') + ) + except PyAsn1Error: + pass + else: + assert 0, 'Local timezone tolerated' + + def testMissingTimezone(self): + try: + assert encoder.encode( + useful.GeneralizedTime('20150501120112.1') + ) + except PyAsn1Error: + pass + else: + assert 0, 'Missing timezone tolerated' + + + def testDecimalCommaPoint(self): + try: + assert encoder.encode( + useful.GeneralizedTime('20150501120112,1Z') + ) + except PyAsn1Error: + pass + else: + assert 0, 'Decimal comma tolerated' + + def testWithSubseconds(self): + assert encoder.encode( + useful.GeneralizedTime('20170801120112.59Z') + ) == ints2octs((24, 18, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 46, 53, 57, 90)) + + def testWithSeconds(self): + assert encoder.encode( + useful.GeneralizedTime('20170801120112Z') + ) == ints2octs((24, 15, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 90)) + + def testWithMinutes(self): + assert encoder.encode( + useful.GeneralizedTime('201708011201Z') + ) == ints2octs((24, 13, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 90)) + + +class UTCTimeEncoderTestCase(BaseTestCase): + def testFractionOfSecond(self): + try: + assert encoder.encode( + useful.UTCTime('150501120112.10Z') + ) + except PyAsn1Error: + pass + else: + assert 0, 'Decimal point tolerated' + + def testMissingTimezone(self): + try: + assert encoder.encode( + useful.UTCTime('150501120112') + ) == ints2octs((23, 13, 49, 53, 48, 53, 48, 49, 49, 50, 48, 49, 49, 50, 90)) + except PyAsn1Error: + pass + else: + assert 0, 'Missing timezone tolerated' + + def testLocalTimezone(self): + try: + assert encoder.encode( + useful.UTCTime('150501120112+0200') + ) + except PyAsn1Error: + pass + else: + assert 0, 'Local timezone tolerated' + + def testWithSeconds(self): + assert encoder.encode( + useful.UTCTime('990801120112Z') + ) == ints2octs((23, 13, 57, 57, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 90)) + + def testWithMinutes(self): + assert encoder.encode( + useful.UTCTime('9908011201Z') + ) == ints2octs((23, 11, 57, 57, 48, 56, 48, 49, 49, 50, 48, 49, 90)) + + +class SequenceOfEncoderTestCase(BaseTestCase): + def testEmpty(self): + s = univ.SequenceOf() + assert encoder.encode(s) == ints2octs((48, 128, 0, 0)) + + def testDefMode1(self): + s = univ.SequenceOf() + s.append(univ.OctetString('a')) + s.append(univ.OctetString('ab')) + assert encoder.encode(s) == ints2octs((48, 128, 4, 1, 97, 4, 2, 97, 98, 0, 0)) + + def testDefMode2(self): + s = univ.SequenceOf() + s.append(univ.OctetString('ab')) + s.append(univ.OctetString('a')) + assert encoder.encode(s) == ints2octs((48, 128, 4, 2, 97, 98, 4, 1, 97, 0, 0)) + + def testDefMode3(self): + s = univ.SequenceOf() + s.append(univ.OctetString('b')) + s.append(univ.OctetString('a')) + assert encoder.encode(s) == ints2octs((48, 128, 4, 1, 98, 4, 1, 97, 0, 0)) + + def testDefMode4(self): + s = univ.SequenceOf() + s.append(univ.OctetString('a')) + s.append(univ.OctetString('b')) + assert encoder.encode(s) == ints2octs((48, 128, 4, 1, 97, 4, 1, 98, 0, 0)) + + +class SequenceOfEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SequenceOf(componentType=univ.OctetString()) + + def testEmpty(self): + self.s.clear() + assert encoder.encode(self.s) == ints2octs((48, 128, 0, 0)) + + def testIndefMode1(self): + self.s.clear() + self.s.append('a') + self.s.append('ab') + assert encoder.encode(self.s) == ints2octs((48, 128, 4, 1, 97, 4, 2, 97, 98, 0, 0)) + + def testIndefMode2(self): + self.s.clear() + self.s.append('ab') + self.s.append('a') + assert encoder.encode(self.s) == ints2octs((48, 128, 4, 2, 97, 98, 4, 1, 97, 0, 0)) + + def testIndefMode3(self): + self.s.clear() + self.s.append('b') + self.s.append('a') + assert encoder.encode(self.s) == ints2octs((48, 128, 4, 1, 98, 4, 1, 97, 0, 0)) + + def testIndefMode4(self): + self.s.clear() + self.s.append('a') + self.s.append('b') + assert encoder.encode(self.s) == ints2octs((48, 128, 4, 1, 97, 4, 1, 98, 0, 0)) + + +class SetOfEncoderTestCase(BaseTestCase): + def testEmpty(self): + s = univ.SetOf() + assert encoder.encode(s) == ints2octs((49, 128, 0, 0)) + + def testDefMode1(self): + s = univ.SetOf() + s.append(univ.OctetString('a')) + s.append(univ.OctetString('ab')) + assert encoder.encode(s) == ints2octs((49, 128, 4, 1, 97, 4, 2, 97, 98, 0, 0)) + + def testDefMode2(self): + s = univ.SetOf() + s.append(univ.OctetString('ab')) + s.append(univ.OctetString('a')) + assert encoder.encode(s) == ints2octs((49, 128, 4, 1, 97, 4, 2, 97, 98, 0, 0)) + + def testDefMode3(self): + s = univ.SetOf() + s.append(univ.OctetString('b')) + s.append(univ.OctetString('a')) + assert encoder.encode(s) == ints2octs((49, 128, 4, 1, 97, 4, 1, 98, 0, 0)) + + def testDefMode4(self): + s = univ.SetOf() + s.append(univ.OctetString('a')) + s.append(univ.OctetString('b')) + assert encoder.encode(s) == ints2octs((49, 128, 4, 1, 97, 4, 1, 98, 0, 0)) + + +class SetOfEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.SetOf(componentType=univ.OctetString()) + + def testEmpty(self): + self.s.clear() + assert encoder.encode(self.s) == ints2octs((49, 128, 0, 0)) + + def testIndefMode1(self): + self.s.clear() + self.s.append('a') + self.s.append('ab') + + assert encoder.encode(self.s) == ints2octs((49, 128, 4, 1, 97, 4, 2, 97, 98, 0, 0)) + + def testIndefMode2(self): + self.s.clear() + self.s.append('ab') + self.s.append('a') + + assert encoder.encode(self.s) == ints2octs((49, 128, 4, 1, 97, 4, 2, 97, 98, 0, 0)) + + def testIndefMode3(self): + self.s.clear() + self.s.append('b') + self.s.append('a') + + assert encoder.encode(self.s) == ints2octs((49, 128, 4, 1, 97, 4, 1, 98, 0, 0)) + + def testIndefMode4(self): + self.s.clear() + self.s.append('a') + self.s.append('b') + + assert encoder.encode(self.s) == ints2octs((49, 128, 4, 1, 97, 4, 1, 98, 0, 0)) + + +class SetEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testIndefMode(self): + assert encoder.encode(self.s) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithOptionalIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithDefaultedIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithOptionalAndDefaultedIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + +class SetEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set(componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null('')), + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)) + )) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0) + + def __initWithOptional(self): + self.s.clear() + self.s.setComponentByPosition(0) + self.s.setComponentByPosition(1, 'quick brown') + + def __initWithDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0) + self.s.setComponentByPosition(2, 1) + + def __initWithOptionalAndDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testIndefMode(self): + self.__init() + assert encoder.encode(self.s) == ints2octs((49, 128, 5, 0, 0, 0)) + + def testWithOptionalIndefMode(self): + self.__initWithOptional() + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithDefaultedIndefMode(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 5, 0, 0, 0)) + + def testWithOptionalAndDefaultedIndefMode(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + +class SetWithChoiceWithSchemaEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + c = univ.Choice(componentType=namedtype.NamedTypes( + namedtype.NamedType('actual', univ.Boolean(0)) + )) + self.s = univ.Set(componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null('')), + namedtype.NamedType('status', c) + )) + + def testIndefMode(self): + self.s.setComponentByPosition(0) + self.s.setComponentByName('status') + self.s.getComponentByName('status').setComponentByPosition(0, 1) + assert encoder.encode(self.s) == ints2octs((49, 128, 1, 1, 255, 5, 0, 0, 0)) + + +class SetEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Set() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testIndefMode(self): + assert encoder.encode(self.s) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithOptionalIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithDefaultedIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + def testWithOptionalAndDefaultedIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0)) + + +class SequenceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testIndefMode(self): + assert encoder.encode(self.s) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testWithOptionalIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testWithDefaultedIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + def testWithOptionalAndDefaultedIndefMode(self): + assert encoder.encode( + self.s + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + +class SequenceEncoderWithSchemaTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null('')), + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)) + ) + ) + + def __init(self): + self.s.clear() + self.s.setComponentByPosition(0) + + def __initWithOptional(self): + self.s.clear() + self.s.setComponentByPosition(0) + self.s.setComponentByPosition(1, 'quick brown') + + def __initWithDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0) + self.s.setComponentByPosition(2, 1) + + def __initWithOptionalAndDefaulted(self): + self.s.clear() + self.s.setComponentByPosition(0, univ.Null('')) + self.s.setComponentByPosition(1, univ.OctetString('quick brown')) + self.s.setComponentByPosition(2, univ.Integer(1)) + + def testIndefMode(self): + self.__init() + assert encoder.encode(self.s) == ints2octs((48, 128, 5, 0, 0, 0)) + + def testWithOptionalIndefMode(self): + self.__initWithOptional() + assert encoder.encode( + self.s + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0)) + + def testWithDefaultedIndefMode(self): + self.__initWithDefaulted() + assert encoder.encode( + self.s + ) == ints2octs((48, 128, 5, 0, 2, 1, 1, 0, 0)) + + def testWithOptionalAndDefaultedIndefMode(self): + self.__initWithOptionalAndDefaulted() + assert encoder.encode( + self.s + ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0)) + + +class NestedOptionalSequenceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + inner = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + outerWithOptional = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('inner', inner), + ) + ) + + outerWithDefault = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.DefaultedNamedType('inner', inner), + ) + ) + + self.s1 = outerWithOptional + self.s2 = outerWithDefault + + def __initOptionalWithDefaultAndOptional(self): + self.s1.clear() + self.s1[0][0] = 'test' + self.s1[0][1] = 123 + return self.s1 + + def __initOptionalWithDefault(self): + self.s1.clear() + self.s1[0][1] = 123 + return self.s1 + + def __initOptionalWithOptional(self): + self.s1.clear() + self.s1[0][0] = 'test' + return self.s1 + + def __initOptional(self): + self.s1.clear() + return self.s1 + + def __initDefaultWithDefaultAndOptional(self): + self.s2.clear() + self.s2[0][0] = 'test' + self.s2[0][1] = 123 + return self.s2 + + def __initDefaultWithDefault(self): + self.s2.clear() + self.s2[0][0] = 'test' + return self.s2 + + def __initDefaultWithOptional(self): + self.s2.clear() + self.s2[0][1] = 123 + return self.s2 + + def testOptionalWithDefaultAndOptional(self): + s = self.__initOptionalWithDefaultAndOptional() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 2, 1, 123, 0, 0, 0, 0)) + + def testOptionalWithDefault(self): + s = self.__initOptionalWithDefault() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 2, 1, 123, 0, 0, 0, 0)) + + def testOptionalWithOptional(self): + s = self.__initOptionalWithOptional() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 0, 0, 0, 0)) + + def testOptional(self): + s = self.__initOptional() + assert encoder.encode(s) == ints2octs((48, 128, 0, 0)) + + def testDefaultWithDefaultAndOptional(self): + s = self.__initDefaultWithDefaultAndOptional() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 2, 1, 123, 0, 0, 0, 0)) + + def testDefaultWithDefault(self): + s = self.__initDefaultWithDefault() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 0, 0, 0, 0)) + + def testDefaultWithOptional(self): + s = self.__initDefaultWithOptional() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 2, 1, 123, 0, 0, 0, 0)) + + +class NestedOptionalChoiceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + layer3 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + layer2 = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('inner', layer3), + namedtype.NamedType('first-name', univ.OctetString()) + ) + ) + + layer1 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('inner', layer2), + ) + ) + + self.s = layer1 + + def __initOptionalWithDefaultAndOptional(self): + self.s.clear() + self.s[0][0][0] = 'test' + self.s[0][0][1] = 123 + return self.s + + def __initOptionalWithDefault(self): + self.s.clear() + self.s[0][0][1] = 123 + return self.s + + def __initOptionalWithOptional(self): + self.s.clear() + self.s[0][0][0] = 'test' + return self.s + + def __initOptional(self): + self.s.clear() + return self.s + + def testOptionalWithDefaultAndOptional(self): + s = self.__initOptionalWithDefaultAndOptional() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 2, 1, 123, 0, 0, 0, 0)) + + def testOptionalWithDefault(self): + s = self.__initOptionalWithDefault() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 2, 1, 123, 0, 0, 0, 0)) + + def testOptionalWithOptional(self): + s = self.__initOptionalWithOptional() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 0, 0, 0, 0)) + + def testOptional(self): + s = self.__initOptional() + assert encoder.encode(s) == ints2octs((48, 128, 0, 0)) + + +class NestedOptionalSequenceOfEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + layer2 = univ.SequenceOf( + componentType=univ.OctetString() + ) + + layer1 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('inner', layer2), + ) + ) + + self.s = layer1 + + def __initOptionalWithValue(self): + self.s.clear() + self.s[0][0] = 'test' + return self.s + + def __initOptional(self): + self.s.clear() + return self.s + + def testOptionalWithValue(self): + s = self.__initOptionalWithValue() + assert encoder.encode(s) == ints2octs((48, 128, 48, 128, 4, 4, 116, 101, 115, 116, 0, 0, 0, 0)) + + def testOptional(self): + s = self.__initOptional() + assert encoder.encode(s) == ints2octs((48, 128, 0, 0)) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/test/type/__init__.py b/third_party/python/pyasn1/tests/codec/der/__init__.py similarity index 100% rename from third_party/python/pyasn1/test/type/__init__.py rename to third_party/python/pyasn1/tests/codec/der/__init__.py diff --git a/third_party/python/pyasn1/tests/codec/der/__main__.py b/third_party/python/pyasn1/tests/codec/der/__main__.py new file mode 100644 index 000000000000..0db3904cfadb --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/der/__main__.py @@ -0,0 +1,20 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.codec.der.test_encoder.suite', + 'tests.codec.der.test_decoder.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/der/test_decoder.py b/third_party/python/pyasn1/tests/codec/der/test_decoder.py new file mode 100644 index 000000000000..6f292fdaa63d --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/der/test_decoder.py @@ -0,0 +1,78 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.codec.der import decoder +from pyasn1.compat.octets import ints2octs, null +from pyasn1.error import PyAsn1Error + + +class BitStringDecoderTestCase(BaseTestCase): + def testShortMode(self): + assert decoder.decode( + ints2octs((3, 127, 6) + (170,) * 125 + (128,)) + ) == (((1, 0) * 501), null) + + def testIndefMode(self): + try: + decoder.decode( + ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'indefinite length encoding tolerated' + + def testDefModeChunked(self): + try: + assert decoder.decode( + ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'chunked encoding tolerated' + + +class OctetStringDecoderTestCase(BaseTestCase): + def testShortMode(self): + assert decoder.decode( + '\004\017Quick brown fox'.encode() + ) == ('Quick brown fox'.encode(), ''.encode()) + + def testIndefMode(self): + try: + decoder.decode( + ints2octs((36, 128, 4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120, 0, 0)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'indefinite length encoding tolerated' + + def testChunkedMode(self): + try: + decoder.decode( + ints2octs((36, 23, 4, 2, 81, 117, 4, 2, 105, 99, 4, 2, 107, 32, 4, 2, 98, 114, 4, 2, 111, 119, 4, 1, 110)) + ) + except PyAsn1Error: + pass + else: + assert 0, 'chunked encoding tolerated' + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/der/test_encoder.py b/third_party/python/pyasn1/tests/codec/der/test_encoder.py new file mode 100644 index 000000000000..3059c0cecf67 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/der/test_encoder.py @@ -0,0 +1,295 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import namedtype, univ +from pyasn1.codec.der import encoder +from pyasn1.compat.octets import ints2octs + + +class OctetStringEncoderTestCase(BaseTestCase): + def testDefModeShort(self): + assert encoder.encode( + univ.OctetString('Quick brown fox') + ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120)) + + def testDefModeLong(self): + assert encoder.encode( + univ.OctetString('Q' * 10000) + ) == ints2octs((4, 130, 39, 16) + (81,) * 10000) + + +class BitStringEncoderTestCase(BaseTestCase): + def testDefModeShort(self): + assert encoder.encode( + univ.BitString((1,)) + ) == ints2octs((3, 2, 7, 128)) + + def testDefModeLong(self): + assert encoder.encode( + univ.BitString((1,) * 80000) + ) == ints2octs((3, 130, 39, 17, 0) + (255,) * 10000) + + +class SetOfEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.SetOf(componentType=univ.OctetString()) + + def testDefMode1(self): + self.s.clear() + self.s.append('a') + self.s.append('ab') + + assert encoder.encode(self.s) == ints2octs((49, 7, 4, 1, 97, 4, 2, 97, 98)) + + def testDefMode2(self): + self.s.clear() + self.s.append('ab') + self.s.append('a') + + assert encoder.encode(self.s) == ints2octs((49, 7, 4, 1, 97, 4, 2, 97, 98)) + + def testDefMode3(self): + self.s.clear() + self.s.append('b') + self.s.append('a') + + assert encoder.encode(self.s) == ints2octs((49, 6, 4, 1, 97, 4, 1, 98)) + + def testDefMode4(self): + self.s.clear() + self.s.append('a') + self.s.append('b') + + assert encoder.encode(self.s) == ints2octs((49, 6, 4, 1, 97, 4, 1, 98)) + +class SetWithChoiceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + c = univ.Choice(componentType=namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString()), + namedtype.NamedType('amount', univ.Boolean())) + ) + + self.s = univ.Set(componentType=namedtype.NamedTypes( + namedtype.NamedType('value', univ.Integer(5)), + namedtype.NamedType('status', c)) + ) + + def testComponentsOrdering1(self): + self.s.setComponentByName('status') + self.s.getComponentByName('status').setComponentByPosition(0, 'A') + assert encoder.encode(self.s) == ints2octs((49, 6, 2, 1, 5, 4, 1, 65)) + + def testComponentsOrdering2(self): + self.s.setComponentByName('status') + self.s.getComponentByName('status').setComponentByPosition(1, True) + assert encoder.encode(self.s) == ints2octs((49, 6, 1, 1, 255, 2, 1, 5)) + + +class NestedOptionalSequenceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + inner = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + outerWithOptional = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('inner', inner), + ) + ) + + outerWithDefault = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.DefaultedNamedType('inner', inner), + ) + ) + + self.s1 = outerWithOptional + self.s2 = outerWithDefault + + def __initOptionalWithDefaultAndOptional(self): + self.s1.clear() + self.s1[0][0] = 'test' + self.s1[0][1] = 123 + return self.s1 + + def __initOptionalWithDefault(self): + self.s1.clear() + self.s1[0][1] = 123 + return self.s1 + + def __initOptionalWithOptional(self): + self.s1.clear() + self.s1[0][0] = 'test' + return self.s1 + + def __initOptional(self): + self.s1.clear() + return self.s1 + + def __initDefaultWithDefaultAndOptional(self): + self.s2.clear() + self.s2[0][0] = 'test' + self.s2[0][1] = 123 + return self.s2 + + def __initDefaultWithDefault(self): + self.s2.clear() + self.s2[0][0] = 'test' + return self.s2 + + def __initDefaultWithOptional(self): + self.s2.clear() + self.s2[0][1] = 123 + return self.s2 + + def testDefModeOptionalWithDefaultAndOptional(self): + s = self.__initOptionalWithDefaultAndOptional() + assert encoder.encode(s) == ints2octs((48, 11, 48, 9, 4, 4, 116, 101, 115, 116, 2, 1, 123)) + + def testDefModeOptionalWithDefault(self): + s = self.__initOptionalWithDefault() + assert encoder.encode(s) == ints2octs((48, 5, 48, 3, 2, 1, 123)) + + def testDefModeOptionalWithOptional(self): + s = self.__initOptionalWithOptional() + assert encoder.encode(s) == ints2octs((48, 8, 48, 6, 4, 4, 116, 101, 115, 116)) + + def testDefModeOptional(self): + s = self.__initOptional() + assert encoder.encode(s) == ints2octs((48, 0)) + + def testDefModeDefaultWithDefaultAndOptional(self): + s = self.__initDefaultWithDefaultAndOptional() + assert encoder.encode(s) == ints2octs((48, 11, 48, 9, 4, 4, 116, 101, 115, 116, 2, 1, 123)) + + def testDefModeDefaultWithDefault(self): + s = self.__initDefaultWithDefault() + assert encoder.encode(s) == ints2octs((48, 8, 48, 6, 4, 4, 116, 101, 115, 116)) + + def testDefModeDefaultWithOptional(self): + s = self.__initDefaultWithOptional() + assert encoder.encode(s) == ints2octs((48, 5, 48, 3, 2, 1, 123)) + + +class NestedOptionalChoiceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + layer3 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('first-name', univ.OctetString()), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + ) + ) + + layer2 = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('inner', layer3), + namedtype.NamedType('first-name', univ.OctetString()) + ) + ) + + layer1 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('inner', layer2), + ) + ) + + self.s = layer1 + + def __initOptionalWithDefaultAndOptional(self): + self.s.clear() + self.s[0][0][0] = 'test' + self.s[0][0][1] = 123 + return self.s + + def __initOptionalWithDefault(self): + self.s.clear() + self.s[0][0][1] = 123 + return self.s + + def __initOptionalWithOptional(self): + self.s.clear() + self.s[0][0][0] = 'test' + return self.s + + def __initOptional(self): + self.s.clear() + return self.s + + def testDefModeOptionalWithDefaultAndOptional(self): + s = self.__initOptionalWithDefaultAndOptional() + assert encoder.encode(s) == ints2octs((48, 11, 48, 9, 4, 4, 116, 101, 115, 116, 2, 1, 123)) + + def testDefModeOptionalWithDefault(self): + s = self.__initOptionalWithDefault() + assert encoder.encode(s) == ints2octs((48, 5, 48, 3, 2, 1, 123)) + + def testDefModeOptionalWithOptional(self): + s = self.__initOptionalWithOptional() + assert encoder.encode(s) == ints2octs((48, 8, 48, 6, 4, 4, 116, 101, 115, 116)) + + def testDefModeOptional(self): + s = self.__initOptional() + assert encoder.encode(s) == ints2octs((48, 0)) + + +class NestedOptionalSequenceOfEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + layer2 = univ.SequenceOf( + componentType=univ.OctetString() + ) + + layer1 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.OptionalNamedType('inner', layer2), + ) + ) + + self.s = layer1 + + def __initOptionalWithValue(self): + self.s.clear() + self.s[0][0] = 'test' + return self.s + + def __initOptional(self): + self.s.clear() + return self.s + + def testDefModeOptionalWithValue(self): + s = self.__initOptionalWithValue() + assert encoder.encode(s) == ints2octs((48, 8, 48, 6, 4, 4, 116, 101, 115, 116)) + + def testDefModeOptional(self): + s = self.__initOptional() + assert encoder.encode(s) == ints2octs((48, 0)) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/native/__init__.py b/third_party/python/pyasn1/tests/codec/native/__init__.py new file mode 100644 index 000000000000..8c3066b2e68f --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/native/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/third_party/python/pyasn1/tests/codec/native/__main__.py b/third_party/python/pyasn1/tests/codec/native/__main__.py new file mode 100644 index 000000000000..89f0e06c23af --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/native/__main__.py @@ -0,0 +1,19 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.codec.native.test_encoder.suite', + 'tests.codec.native.test_decoder.suite'] +) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/native/test_decoder.py b/third_party/python/pyasn1/tests/codec/native/test_decoder.py new file mode 100644 index 000000000000..c3854afb67b4 --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/native/test_decoder.py @@ -0,0 +1,123 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import namedtype, univ +from pyasn1.codec.native import decoder +from pyasn1.error import PyAsn1Error + + +class BadAsn1SpecTestCase(BaseTestCase): + def testBadSpec(self): + try: + decoder.decode('', asn1Spec='not an Asn1Item') + except PyAsn1Error: + pass + else: + assert 0, 'Invalid asn1Spec accepted' + + +class IntegerDecoderTestCase(BaseTestCase): + def testPosInt(self): + assert decoder.decode(12, asn1Spec=univ.Integer()) == univ.Integer(12) + + def testNegInt(self): + assert decoder.decode(-12, asn1Spec=univ.Integer()) == univ.Integer(-12) + + +class BooleanDecoderTestCase(BaseTestCase): + def testTrue(self): + assert decoder.decode(True, asn1Spec=univ.Boolean()) == univ.Boolean(True) + + def testTrueNeg(self): + assert decoder.decode(False, asn1Spec=univ.Boolean()) == univ.Boolean(False) + + +class BitStringDecoderTestCase(BaseTestCase): + def testSimple(self): + assert decoder.decode('11111111', asn1Spec=univ.BitString()) == univ.BitString(hexValue='ff') + + +class OctetStringDecoderTestCase(BaseTestCase): + def testSimple(self): + assert decoder.decode('Quick brown fox', asn1Spec=univ.OctetString()) == univ.OctetString('Quick brown fox') + + +class NullDecoderTestCase(BaseTestCase): + def testNull(self): + assert decoder.decode(None, asn1Spec=univ.Null()) == univ.Null() + + +class ObjectIdentifierDecoderTestCase(BaseTestCase): + def testOne(self): + assert decoder.decode('1.3.6.11', asn1Spec=univ.ObjectIdentifier()) == univ.ObjectIdentifier('1.3.6.11') + + +class RealDecoderTestCase(BaseTestCase): + def testSimple(self): + assert decoder.decode(1.33, asn1Spec=univ.Real()) == univ.Real(1.33) + + +class SequenceDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null()), + namedtype.NamedType('first-name', univ.OctetString()), + namedtype.NamedType('age', univ.Integer(33)) + ) + ) + + def testSimple(self): + s = self.s.clone() + s[0] = univ.Null() + s[1] = univ.OctetString('xx') + s[2] = univ.Integer(33) + assert decoder.decode({'place-holder': None, 'first-name': 'xx', 'age': 33}, asn1Spec=self.s) == s + + +class ChoiceDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null()), + namedtype.NamedType('first-name', univ.OctetString()), + namedtype.NamedType('age', univ.Integer(33)) + ) + ) + + def testSimple(self): + s = self.s.clone() + s[1] = univ.OctetString('xx') + assert decoder.decode({'first-name': 'xx'}, asn1Spec=self.s) == s + + +class AnyDecoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.Any() + + def testSimple(self): + assert decoder.decode('fox', asn1Spec=univ.Any()) == univ.Any('fox') + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/codec/native/test_encoder.py b/third_party/python/pyasn1/tests/codec/native/test_encoder.py new file mode 100644 index 000000000000..cfa5b8947c9e --- /dev/null +++ b/third_party/python/pyasn1/tests/codec/native/test_encoder.py @@ -0,0 +1,144 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import namedtype, univ +from pyasn1.codec.native import encoder +from pyasn1.compat.octets import str2octs +from pyasn1.error import PyAsn1Error + + +class BadAsn1SpecTestCase(BaseTestCase): + def testBadValueType(self): + try: + encoder.encode('not an Asn1Item') + + except PyAsn1Error: + pass + + else: + assert 0, 'Invalid value type accepted' + + +class IntegerEncoderTestCase(BaseTestCase): + def testPosInt(self): + assert encoder.encode(univ.Integer(12)) == 12 + + def testNegInt(self): + assert encoder.encode(univ.Integer(-12)) == -12 + + +class BooleanEncoderTestCase(BaseTestCase): + def testTrue(self): + assert encoder.encode(univ.Boolean(1)) is True + + def testFalse(self): + assert encoder.encode(univ.Boolean(0)) is False + + +class BitStringEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.b = univ.BitString((1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1)) + + def testValue(self): + assert encoder.encode(self.b) == '101010011000101' + + +class OctetStringEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.o = univ.OctetString('Quick brown fox') + + def testValue(self): + assert encoder.encode(self.o) == str2octs('Quick brown fox') + + +class NullEncoderTestCase(BaseTestCase): + def testNull(self): + assert encoder.encode(univ.Null('')) is None + + +class ObjectIdentifierEncoderTestCase(BaseTestCase): + def testOne(self): + assert encoder.encode(univ.ObjectIdentifier((1, 3, 6, 0, 12345))) == '1.3.6.0.12345' + + +class RealEncoderTestCase(BaseTestCase): + def testChar(self): + assert encoder.encode(univ.Real((123, 10, 11))) == 1.23e+13 + + def testPlusInf(self): + assert encoder.encode(univ.Real('inf')) == float('inf') + + def testMinusInf(self): + assert encoder.encode(univ.Real('-inf')) == float('-inf') + + +class SequenceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.Sequence(componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null('')), + namedtype.OptionalNamedType('first-name', univ.OctetString('')), + namedtype.DefaultedNamedType('age', univ.Integer(33)), + )) + + def testSimple(self): + s = self.s.clone() + s[0] = univ.Null('') + s[1] = 'abc' + s[2] = 123 + assert encoder.encode(s) == {'place-holder': None, 'first-name': str2octs('abc'), 'age': 123} + + +class ChoiceEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('place-holder', univ.Null('')), + namedtype.NamedType('number', univ.Integer(0)), + namedtype.NamedType('string', univ.OctetString()) + ) + ) + + def testEmpty(self): + try: + encoder.encode(self.s) + except PyAsn1Error: + pass + else: + assert False, 'encoded unset choice' + + def testFilled(self): + self.s.setComponentByPosition(0, univ.Null('')) + assert encoder.encode(self.s) == {'place-holder': None} + + +class AnyEncoderTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s = univ.Any(encoder.encode(univ.OctetString('fox'))) + + def testSimple(self): + assert encoder.encode(self.s) == str2octs('fox') + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/compat/__init__.py b/third_party/python/pyasn1/tests/compat/__init__.py new file mode 100644 index 000000000000..8c3066b2e68f --- /dev/null +++ b/third_party/python/pyasn1/tests/compat/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/third_party/python/pyasn1/tests/compat/__main__.py b/third_party/python/pyasn1/tests/compat/__main__.py new file mode 100644 index 000000000000..ce26562d524f --- /dev/null +++ b/third_party/python/pyasn1/tests/compat/__main__.py @@ -0,0 +1,21 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.compat.test_binary.suite', + 'tests.compat.test_integer.suite', + 'tests.compat.test_octets.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/compat/test_binary.py b/third_party/python/pyasn1/tests/compat/test_binary.py new file mode 100644 index 000000000000..ce3d1ef1c69e --- /dev/null +++ b/third_party/python/pyasn1/tests/compat/test_binary.py @@ -0,0 +1,56 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.compat import binary + + +class BinaryTestCase(BaseTestCase): + + def test_bin_zero(self): + assert '0b0' == binary.bin(0) + + + def test_bin_noarg(self): + try: + binary.bin() + + except TypeError: + pass + + except: + assert 0, 'bin() tolerates no arguments' + + + def test_bin_allones(self): + assert '0b1111111111111111111111111111111111111111111111111111111111111111' == binary.bin(0xffffffffffffffff) + + + def test_bin_allzeros(self): + assert '0b0' == binary.bin(0x0000000) + + + + def test_bin_pos(self): + assert '0b1000000010000000100000001' == binary.bin(0x01010101) + + + def test_bin_neg(self): + assert '-0b1000000010000000100000001' == binary.bin(-0x01010101) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/compat/test_integer.py b/third_party/python/pyasn1/tests/compat/test_integer.py new file mode 100644 index 000000000000..22aadd9477dd --- /dev/null +++ b/third_party/python/pyasn1/tests/compat/test_integer.py @@ -0,0 +1,53 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.compat import integer + + +class IntegerTestCase(BaseTestCase): + + if sys.version_info[0] > 2: + + def test_from_bytes_zero(self): + assert 0 == integer.from_bytes(bytes([0]), signed=False) + + def test_from_bytes_unsigned(self): + assert -66051 == integer.from_bytes(bytes([254, 253, 253]), signed=True) + + def test_from_bytes_signed(self): + assert 66051 == integer.from_bytes(bytes([0, 1, 2, 3]), signed=False) + + def test_from_bytes_empty(self): + assert 0 == integer.from_bytes(bytes([])) + + else: + + def test_from_bytes_zero(self): + assert 0 == integer.from_bytes('\x00', signed=False) + + def test_from_bytes_unsigned(self): + assert -66051 == integer.from_bytes('\xfe\xfd\xfd', signed=True) + + def test_from_bytes_signed(self): + assert 66051 == integer.from_bytes('\x01\x02\x03', signed=False) + + def test_from_bytes_empty(self): + assert 0 == integer.from_bytes('') + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/compat/test_octets.py b/third_party/python/pyasn1/tests/compat/test_octets.py new file mode 100644 index 000000000000..82382f7ef8f8 --- /dev/null +++ b/third_party/python/pyasn1/tests/compat/test_octets.py @@ -0,0 +1,117 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.compat import octets + + +class OctetsTestCase(BaseTestCase): + + if sys.version_info[0] > 2: + + def test_ints2octs(self): + assert [1, 2, 3] == list(octets.ints2octs([1, 2, 3])) + + def test_ints2octs_empty(self): + assert not octets.ints2octs([]) + + def test_int2oct(self): + assert [12] == list(octets.int2oct(12)) + + def test_octs2ints(self): + assert [1, 2, 3] == list(octets.octs2ints(bytes([1, 2, 3]))) + + def test_octs2ints_empty(self): + assert not octets.octs2ints(bytes([])) + + def test_oct2int(self): + assert 12 == octets.oct2int(bytes([12]))[0] + + def test_str2octs(self): + assert bytes([1, 2, 3]) == octets.str2octs('\x01\x02\x03') + + def test_str2octs_empty(self): + assert not octets.str2octs('') + + def test_octs2str(self): + assert '\x01\x02\x03' == octets.octs2str(bytes([1, 2, 3])) + + def test_octs2str_empty(self): + assert not octets.octs2str(bytes([])) + + def test_isOctetsType(self): + assert octets.isOctetsType('abc') == False + assert octets.isOctetsType(123) == False + assert octets.isOctetsType(bytes()) == True + + def test_isStringType(self): + assert octets.isStringType('abc') == True + assert octets.isStringType(123) == False + assert octets.isStringType(bytes()) == False + + def test_ensureString(self): + assert 'abc'.encode() == octets.ensureString('abc'.encode()) + assert bytes([1, 2, 3]) == octets.ensureString([1, 2, 3]) + + else: + + def test_ints2octs(self): + assert '\x01\x02\x03' == octets.ints2octs([1, 2, 3]) + + def test_ints2octs_empty(self): + assert not octets.ints2octs([]) + + def test_int2oct(self): + assert '\x0c' == octets.int2oct(12) + + def test_octs2ints(self): + assert [1, 2, 3] == octets.octs2ints('\x01\x02\x03') + + def test_octs2ints_empty(self): + assert not octets.octs2ints('') + + def test_oct2int(self): + assert 12 == octets.oct2int('\x0c') + + def test_str2octs(self): + assert '\x01\x02\x03' == octets.str2octs('\x01\x02\x03') + + def test_str2octs_empty(self): + assert not octets.str2octs('') + + def test_octs2str(self): + assert '\x01\x02\x03' == octets.octs2str('\x01\x02\x03') + + def test_octs2str_empty(self): + assert not octets.octs2str('') + + def test_isOctetsType(self): + assert octets.isOctetsType('abc') == True + assert octets.isOctetsType(123) == False + assert octets.isOctetsType(unicode('abc')) == False + + def test_isStringType(self): + assert octets.isStringType('abc') == True + assert octets.isStringType(123) == False + assert octets.isStringType(unicode('abc')) == True + + def test_ensureString(self): + assert 'abc' == octets.ensureString('abc') + assert '123' == octets.ensureString(123) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/test_debug.py b/third_party/python/pyasn1/tests/test_debug.py new file mode 100644 index 000000000000..e4616bb57631 --- /dev/null +++ b/third_party/python/pyasn1/tests/test_debug.py @@ -0,0 +1,42 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1 import debug +from pyasn1 import error + +class DebugCaseBase(BaseTestCase): + def testKnownFlags(self): + debug.setLogger(0) + debug.setLogger(debug.Debug('all', 'encoder', 'decoder')) + debug.setLogger(0) + + def testUnknownFlags(self): + try: + debug.setLogger(debug.Debug('all', 'unknown', loggerName='xxx')) + + except error.PyAsn1Error: + debug.setLogger(0) + return + + else: + debug.setLogger(0) + assert 0, 'unknown debug flag tolerated' + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/type/__init__.py b/third_party/python/pyasn1/tests/type/__init__.py new file mode 100644 index 000000000000..8c3066b2e68f --- /dev/null +++ b/third_party/python/pyasn1/tests/type/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/third_party/python/pyasn1/tests/type/__main__.py b/third_party/python/pyasn1/tests/type/__main__.py new file mode 100644 index 000000000000..0ad51ce3a9ca --- /dev/null +++ b/third_party/python/pyasn1/tests/type/__main__.py @@ -0,0 +1,25 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +try: + import unittest2 as unittest + +except ImportError: + import unittest + +suite = unittest.TestLoader().loadTestsFromNames( + ['tests.type.test_constraint.suite', + 'tests.type.test_namedtype.suite', + 'tests.type.test_namedval.suite', + 'tests.type.test_tag.suite', + 'tests.type.test_univ.suite', + 'tests.type.test_char.suite', + 'tests.type.test_useful.suite'] +) + + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/type/test_char.py b/third_party/python/pyasn1/tests/type/test_char.py new file mode 100644 index 000000000000..74550c00ecb3 --- /dev/null +++ b/third_party/python/pyasn1/tests/type/test_char.py @@ -0,0 +1,156 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import char, univ, constraint +from pyasn1.compat.octets import ints2octs +from pyasn1.error import PyAsn1Error + + +class AbstractStringTestCase(object): + + initializer = () + encoding = 'us-ascii' + asn1Type = None + + def setUp(self): + BaseTestCase.setUp(self) + + self.asn1String = self.asn1Type(ints2octs(self.initializer), encoding=self.encoding) + self.pythonString = ints2octs(self.initializer).decode(self.encoding) + + def testUnicode(self): + assert self.asn1String == self.pythonString, 'unicode init fails' + + def testLength(self): + assert len(self.asn1String) == len(self.pythonString), 'unicode len() fails' + + def testSizeConstraint(self): + asn1Spec = self.asn1Type(subtypeSpec=constraint.ValueSizeConstraint(1, 1)) + + try: + asn1Spec.clone(self.pythonString) + except PyAsn1Error: + pass + else: + assert False, 'Size constraint tolerated' + + try: + asn1Spec.clone(self.pythonString[0]) + except PyAsn1Error: + assert False, 'Size constraint failed' + + def testSerialized(self): + if sys.version_info[0] < 3: + assert str(self.asn1String) == self.pythonString.encode(self.encoding), '__str__() fails' + else: + assert bytes(self.asn1String) == self.pythonString.encode(self.encoding), '__str__() fails' + + def testPrintable(self): + if sys.version_info[0] < 3: + assert unicode(self.asn1String) == self.pythonString, '__str__() fails' + else: + assert str(self.asn1String) == self.pythonString, '__str__() fails' + + def testInit(self): + assert self.asn1Type(self.pythonString) == self.pythonString + assert self.asn1Type(self.pythonString.encode(self.encoding)) == self.pythonString + assert self.asn1Type(univ.OctetString(self.pythonString.encode(self.encoding))) == self.pythonString + assert self.asn1Type(self.asn1Type(self.pythonString)) == self.pythonString + assert self.asn1Type(self.initializer, encoding=self.encoding) == self.pythonString + + def testInitFromAsn1(self): + assert self.asn1Type(self.asn1Type(self.pythonString)) == self.pythonString + assert self.asn1Type(univ.OctetString(self.pythonString.encode(self.encoding), encoding=self.encoding)) == self.pythonString + + def testAsOctets(self): + assert self.asn1String.asOctets() == self.pythonString.encode(self.encoding), 'testAsOctets() fails' + + def testAsNumbers(self): + assert self.asn1String.asNumbers() == self.initializer, 'testAsNumbers() fails' + + def testSeq(self): + assert self.asn1String[0] == self.pythonString[0], '__getitem__() fails' + + def testEmpty(self): + try: + str(self.asn1Type()) + except PyAsn1Error: + pass + else: + assert 0, 'Value operation on ASN1 type tolerated' + + def testAdd(self): + assert self.asn1String + self.pythonString.encode(self.encoding) == self.pythonString + self.pythonString, '__add__() fails' + + def testRadd(self): + assert self.pythonString.encode(self.encoding) + self.asn1String == self.pythonString + self.pythonString, '__radd__() fails' + + def testMul(self): + assert self.asn1String * 2 == self.pythonString * 2, '__mul__() fails' + + def testRmul(self): + assert 2 * self.asn1String == 2 * self.pythonString, '__rmul__() fails' + + def testContains(self): + assert self.pythonString in self.asn1String + assert self.pythonString + self.pythonString not in self.asn1String + + if sys.version_info[:2] > (2, 4): + def testReverse(self): + assert list(reversed(self.asn1String)) == list(reversed(self.pythonString)) + + +class VisibleStringTestCase(AbstractStringTestCase, BaseTestCase): + + initializer = (97, 102) + encoding = 'us-ascii' + asn1Type = char.VisibleString + + +class GeneralStringTestCase(AbstractStringTestCase, BaseTestCase): + + initializer = (169, 174) + encoding = 'iso-8859-1' + asn1Type = char.GeneralString + + +class UTF8StringTestCase(AbstractStringTestCase, BaseTestCase): + + initializer = (209, 132, 208, 176) + encoding = 'utf-8' + asn1Type = char.UTF8String + + +class BMPStringTestCase(AbstractStringTestCase, BaseTestCase): + + initializer = (4, 48, 4, 68) + encoding = 'utf-16-be' + asn1Type = char.BMPString + + +if sys.version_info[0] > 2: + + # Somehow comparison of UTF-32 encoded strings does not work in Py2 + + class UniversalStringTestCase(AbstractStringTestCase, BaseTestCase): + initializer = (0, 0, 4, 48, 0, 0, 4, 68) + encoding = 'utf-32-be' + asn1Type = char.UniversalString + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/test/type/test_constraint.py b/third_party/python/pyasn1/tests/type/test_constraint.py similarity index 71% rename from third_party/python/pyasn1/test/type/test_constraint.py rename to third_party/python/pyasn1/tests/type/test_constraint.py index 3457c0fc375f..1dbffb1be5c7 100644 --- a/third_party/python/pyasn1/test/type/test_constraint.py +++ b/third_party/python/pyasn1/tests/type/test_constraint.py @@ -1,27 +1,41 @@ -from pyasn1.type import constraint, error -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest + +except ImportError: import unittest -class SingleValueConstraintTestCase(unittest.TestCase): - def setUp(self): - self.c1 = constraint.SingleValueConstraint(1,2) - self.c2 = constraint.SingleValueConstraint(3,4) +from tests.base import BaseTestCase + +from pyasn1.type import constraint, error + + +class SingleValueConstraintTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.c1 = constraint.SingleValueConstraint(1, 2) + self.c2 = constraint.SingleValueConstraint(3, 4) + + def testCmp(self): + assert self.c1 == self.c1, 'comparation fails' + + def testHash(self): + assert hash(self.c1) != hash(self.c2), 'hash() fails' - def testCmp(self): assert self.c1 == self.c1, 'comparation fails' - def testHash(self): assert hash(self.c1) != hash(self.c2), 'hash() fails' def testGoodVal(self): try: self.c1(1) + except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(4) @@ -30,17 +44,20 @@ class SingleValueConstraintTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' -class ContainedSubtypeConstraintTestCase(unittest.TestCase): + +class ContainedSubtypeConstraintTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) self.c1 = constraint.ContainedSubtypeConstraint( constraint.SingleValueConstraint(12) - ) + ) def testGoodVal(self): try: self.c1(12) except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(4) @@ -49,15 +66,18 @@ class ContainedSubtypeConstraintTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' -class ValueRangeConstraintTestCase(unittest.TestCase): + +class ValueRangeConstraintTestCase(BaseTestCase): def setUp(self): - self.c1 = constraint.ValueRangeConstraint(1,4) + BaseTestCase.setUp(self) + self.c1 = constraint.ValueRangeConstraint(1, 4) def testGoodVal(self): try: self.c1(1) except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(-5) @@ -66,15 +86,18 @@ class ValueRangeConstraintTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' -class ValueSizeConstraintTestCase(unittest.TestCase): + +class ValueSizeConstraintTestCase(BaseTestCase): def setUp(self): - self.c1 = constraint.ValueSizeConstraint(1,2) + BaseTestCase.setUp(self) + self.c1 = constraint.ValueSizeConstraint(1, 2) def testGoodVal(self): try: self.c1('a') except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1('abc') @@ -83,6 +106,7 @@ class ValueSizeConstraintTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' + class PermittedAlphabetConstraintTestCase(SingleValueConstraintTestCase): def setUp(self): self.c1 = constraint.PermittedAlphabetConstraint('A', 'B', 'C') @@ -93,6 +117,7 @@ class PermittedAlphabetConstraintTestCase(SingleValueConstraintTestCase): self.c1('A') except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1('E') @@ -101,37 +126,41 @@ class PermittedAlphabetConstraintTestCase(SingleValueConstraintTestCase): else: assert 0, 'constraint check fails' -class ConstraintsIntersectionTestCase(unittest.TestCase): + +class ConstraintsIntersectionTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) self.c1 = constraint.ConstraintsIntersection( constraint.SingleValueConstraint(4), constraint.ValueRangeConstraint(2, 4) - ) + ) def testCmp1(self): assert constraint.SingleValueConstraint(4) in self.c1, '__cmp__() fails' def testCmp2(self): assert constraint.SingleValueConstraint(5) not in self.c1, \ - '__cmp__() fails' + '__cmp__() fails' def testCmp3(self): c = constraint.ConstraintsUnion(constraint.ConstraintsIntersection( constraint.SingleValueConstraint(4), - constraint.ValueRangeConstraint(2, 4) - )) + constraint.ValueRangeConstraint(2, 4)) + ) assert self.c1 in c, '__cmp__() fails' + def testCmp4(self): c = constraint.ConstraintsUnion( constraint.ConstraintsIntersection(constraint.SingleValueConstraint(5)) - ) + ) assert self.c1 not in c, '__cmp__() fails' - + def testGoodVal(self): try: self.c1(4) except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(-5) @@ -140,11 +169,12 @@ class ConstraintsIntersectionTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' -class InnerTypeConstraintTestCase(unittest.TestCase): + +class InnerTypeConstraintTestCase(BaseTestCase): def testConst1(self): c = constraint.InnerTypeConstraint( constraint.SingleValueConstraint(4) - ) + ) try: c(4, 32) except error.ValueConstraintError: @@ -155,43 +185,47 @@ class InnerTypeConstraintTestCase(unittest.TestCase): pass else: assert 0, 'constraint check fails' + def testConst2(self): c = constraint.InnerTypeConstraint( (0, constraint.SingleValueConstraint(4), 'PRESENT'), (1, constraint.SingleValueConstraint(4), 'ABSENT') - ) + ) try: c(4, 0) except error.ValueConstraintError: raise - assert 0, 'constraint check fails' + assert 0, 'constraint check fails' try: c(4, 1) except error.ValueConstraintError: pass else: - assert 0, 'constraint check fails' + assert 0, 'constraint check fails' try: c(3, 0) except error.ValueConstraintError: pass else: - assert 0, 'constraint check fails' + assert 0, 'constraint check fails' -# Constraints compositions + # Constraints compositions -class ConstraintsIntersectionTestCase(unittest.TestCase): + +class ConstraintsIntersectionRangeTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) self.c1 = constraint.ConstraintsIntersection( constraint.ValueRangeConstraint(1, 9), constraint.ValueRangeConstraint(2, 5) - ) + ) def testGoodVal(self): try: self.c1(3) except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(0) @@ -200,12 +234,14 @@ class ConstraintsIntersectionTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' -class ConstraintsUnionTestCase(unittest.TestCase): + +class ConstraintsUnionTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) self.c1 = constraint.ConstraintsUnion( constraint.SingleValueConstraint(5), constraint.ValueRangeConstraint(1, 3) - ) + ) def testGoodVal(self): try: @@ -213,6 +249,7 @@ class ConstraintsUnionTestCase(unittest.TestCase): self.c1(5) except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(-5) @@ -221,17 +258,20 @@ class ConstraintsUnionTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' -class ConstraintsExclusionTestCase(unittest.TestCase): + +class ConstraintsExclusionTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) self.c1 = constraint.ConstraintsExclusion( constraint.ValueRangeConstraint(2, 4) - ) + ) def testGoodVal(self): try: self.c1(6) except error.ValueConstraintError: assert 0, 'constraint check fails' + def testBadVal(self): try: self.c1(2) @@ -240,41 +280,55 @@ class ConstraintsExclusionTestCase(unittest.TestCase): else: assert 0, 'constraint check fails' + # Constraints derivations -class DirectDerivationTestCase(unittest.TestCase): +class DirectDerivationTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) + self.c1 = constraint.SingleValueConstraint(5) + self.c2 = constraint.ConstraintsUnion( self.c1, constraint.ValueRangeConstraint(1, 3) - ) + ) def testGoodVal(self): assert self.c1.isSuperTypeOf(self.c2), 'isSuperTypeOf failed' - assert not self.c1.isSubTypeOf(self.c2) , 'isSubTypeOf failed' - def testBadVal(self): - assert not self.c2.isSuperTypeOf(self.c1) , 'isSuperTypeOf failed' - assert self.c2.isSubTypeOf(self.c1) , 'isSubTypeOf failed' + assert not self.c1.isSubTypeOf(self.c2), 'isSubTypeOf failed' -class IndirectDerivationTestCase(unittest.TestCase): + def testBadVal(self): + assert not self.c2.isSuperTypeOf(self.c1), 'isSuperTypeOf failed' + assert self.c2.isSubTypeOf(self.c1), 'isSubTypeOf failed' + + +class IndirectDerivationTestCase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) + self.c1 = constraint.ConstraintsIntersection( constraint.ValueRangeConstraint(1, 30) - ) + ) + self.c2 = constraint.ConstraintsIntersection( self.c1, constraint.ValueRangeConstraint(1, 20) - ) + ) + self.c2 = constraint.ConstraintsIntersection( self.c2, constraint.ValueRangeConstraint(1, 10) - ) + ) def testGoodVal(self): assert self.c1.isSuperTypeOf(self.c2), 'isSuperTypeOf failed' - assert not self.c1.isSubTypeOf(self.c2) , 'isSubTypeOf failed' - def testBadVal(self): - assert not self.c2.isSuperTypeOf(self.c1) , 'isSuperTypeOf failed' - assert self.c2.isSubTypeOf(self.c1) , 'isSubTypeOf failed' - -if __name__ == '__main__': unittest.main() + assert not self.c1.isSubTypeOf(self.c2), 'isSubTypeOf failed' -# how to apply size constriants to constructed types? + def testBadVal(self): + assert not self.c2.isSuperTypeOf(self.c1), 'isSuperTypeOf failed' + assert self.c2.isSubTypeOf(self.c1), 'isSubTypeOf failed' + +# TODO: how to apply size constraints to constructed types? + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/type/test_namedtype.py b/third_party/python/pyasn1/tests/type/test_namedtype.py new file mode 100644 index 000000000000..65f9d6533eb0 --- /dev/null +++ b/third_party/python/pyasn1/tests/type/test_namedtype.py @@ -0,0 +1,147 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import namedtype, univ +from pyasn1.error import PyAsn1Error + + +class NamedTypeCaseBase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.e = namedtype.NamedType('age', univ.Integer(0)) + + def testIter(self): + n, t = self.e + assert n == 'age' or t == univ.Integer(), 'unpack fails' + + def testRepr(self): + assert eval(repr(self.e), {'NamedType': namedtype.NamedType, 'Integer': univ.Integer}) == self.e, 'repr() fails' + + +class NamedTypesCaseBase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.e = namedtype.NamedTypes( + namedtype.NamedType('first-name', univ.OctetString('')), + namedtype.OptionalNamedType('age', univ.Integer(0)), + namedtype.NamedType('family-name', univ.OctetString('')) + ) + + def testRepr(self): + assert eval( + repr(self.e), { + 'NamedTypes': namedtype.NamedTypes, + 'NamedType': namedtype.NamedType, + 'OptionalNamedType': namedtype.OptionalNamedType, + 'Integer': univ.Integer, + 'OctetString': univ.OctetString + } + ) == self.e, 'repr() fails' + + def testContains(self): + assert 'first-name' in self.e + assert '' not in self.e + + # noinspection PyUnusedLocal + def testGetItem(self): + assert self.e[0] == namedtype.NamedType('first-name', univ.OctetString('')) + + def testIter(self): + assert list(self.e) == ['first-name', 'age', 'family-name'] + + def testGetTypeByPosition(self): + assert self.e.getTypeByPosition(0) == univ.OctetString(''), \ + 'getTypeByPosition() fails' + + def testGetNameByPosition(self): + assert self.e.getNameByPosition(0) == 'first-name', \ + 'getNameByPosition() fails' + + def testGetPositionByName(self): + assert self.e.getPositionByName('first-name') == 0, \ + 'getPositionByName() fails' + + def testGetTypesNearPosition(self): + assert self.e.getTagMapNearPosition(0).presentTypes == { + univ.OctetString.tagSet: univ.OctetString('') + } + assert self.e.getTagMapNearPosition(1).presentTypes == { + univ.Integer.tagSet: univ.Integer(0), + univ.OctetString.tagSet: univ.OctetString('') + } + assert self.e.getTagMapNearPosition(2).presentTypes == { + univ.OctetString.tagSet: univ.OctetString('') + } + + def testGetTagMap(self): + assert self.e.tagMap.presentTypes == { + univ.OctetString.tagSet: univ.OctetString(''), + univ.Integer.tagSet: univ.Integer(0) + } + + def testStrTagMap(self): + assert 'TagMap' in str(self.e.tagMap) + assert 'OctetString' in str(self.e.tagMap) + assert 'Integer' in str(self.e.tagMap) + + def testReprTagMap(self): + assert 'TagMap' in repr(self.e.tagMap) + assert 'OctetString' in repr(self.e.tagMap) + assert 'Integer' in repr(self.e.tagMap) + + def testGetTagMapWithDups(self): + try: + self.e.tagMapUnique[0] + except PyAsn1Error: + pass + else: + assert 0, 'Duped types not noticed' + + def testGetPositionNearType(self): + assert self.e.getPositionNearType(univ.OctetString.tagSet, 0) == 0 + assert self.e.getPositionNearType(univ.Integer.tagSet, 1) == 1 + assert self.e.getPositionNearType(univ.OctetString.tagSet, 2) == 2 + + +class OrderedNamedTypesCaseBase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.e = namedtype.NamedTypes( + namedtype.NamedType('first-name', univ.OctetString('')), + namedtype.NamedType('age', univ.Integer(0)) + ) + + def testGetTypeByPosition(self): + assert self.e.getTypeByPosition(0) == univ.OctetString(''), \ + 'getTypeByPosition() fails' + + +class DuplicateNamedTypesCaseBase(BaseTestCase): + def testDuplicateDefaultTags(self): + nt = namedtype.NamedTypes( + namedtype.NamedType('first-name', univ.Any()), + namedtype.NamedType('age', univ.Any()) + ) + + assert isinstance(nt.tagMap, namedtype.NamedTypes.PostponedError) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/type/test_namedval.py b/third_party/python/pyasn1/tests/type/test_namedval.py new file mode 100644 index 000000000000..215a3a1d0d13 --- /dev/null +++ b/third_party/python/pyasn1/tests/type/test_namedval.py @@ -0,0 +1,58 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import namedval + + +class NamedValuesCaseBase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.e = namedval.NamedValues(('off', 0), ('on', 1)) + + def testDict(self): + assert set(self.e.items()) == set([('off', 0), ('on', 1)]) + assert set(self.e.keys()) == set(['off', 'on']) + assert set(self.e) == set(['off', 'on']) + assert set(self.e.values()) == set([0, 1]) + assert 'on' in self.e and 'off' in self.e and 'xxx' not in self.e + assert 0 in self.e and 1 in self.e and 2 not in self.e + + def testInit(self): + assert namedval.NamedValues(off=0, on=1) == {'off': 0, 'on': 1} + assert namedval.NamedValues('off', 'on') == {'off': 0, 'on': 1} + assert namedval.NamedValues(('c', 0)) == {'c': 0} + assert namedval.NamedValues('a', 'b', ('c', 0), d=1) == {'c': 0, 'd': 1, 'a': 2, 'b': 3} + + def testLen(self): + assert len(self.e) == 2 + assert len(namedval.NamedValues()) == 0 + + def testAdd(self): + assert namedval.NamedValues(off=0) + namedval.NamedValues(on=1) == {'off': 0, 'on': 1} + + def testClone(self): + assert namedval.NamedValues(off=0).clone(('on', 1)) == {'off': 0, 'on': 1} + assert namedval.NamedValues(off=0).clone(on=1) == {'off': 0, 'on': 1} + + def testStrRepr(self): + assert str(self.e) + assert repr(self.e) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/test/type/test_tag.py b/third_party/python/pyasn1/tests/type/test_tag.py similarity index 69% rename from third_party/python/pyasn1/test/type/test_tag.py rename to third_party/python/pyasn1/tests/type/test_tag.py index 78146dca2f4a..57121e82dcf7 100644 --- a/third_party/python/pyasn1/test/type/test_tag.py +++ b/third_party/python/pyasn1/tests/type/test_tag.py @@ -1,20 +1,34 @@ -from pyasn1.type import tag -from pyasn1.error import PyAsn1Error -from sys import version_info -if version_info[0:2] < (2, 7) or \ - version_info[0:2] in ( (3, 0), (3, 1) ): - try: - import unittest2 as unittest - except ImportError: - import unittest -else: +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys + +try: + import unittest2 as unittest + +except ImportError: import unittest -class TagTestCaseBase(unittest.TestCase): +from tests.base import BaseTestCase + +from pyasn1.type import tag + + +class TagTestCaseBase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) self.t1 = tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3) self.t2 = tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 3) - + + +class TagReprTestCase(TagTestCaseBase): + def testRepr(self): + assert eval(repr(self.t1), {'Tag': tag.Tag}) == self.t1, 'repr() fails' + + class TagCmpTestCase(TagTestCaseBase): def testCmp(self): assert self.t1 == self.t2, 'tag comparation fails' @@ -27,14 +41,24 @@ class TagCmpTestCase(TagTestCaseBase): self.t1[1] == self.t2[1] and \ self.t1[2] == self.t2[2], 'tag sequence protocol fails' -class TagSetTestCaseBase(unittest.TestCase): + +class TagSetTestCaseBase(BaseTestCase): def setUp(self): + BaseTestCase.setUp(self) + self.ts1 = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) - ) + ) + self.ts2 = tag.initTagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) - ) + ) + + +class TagSetReprTestCase(TagSetTestCaseBase): + def testRepr(self): + assert eval(repr(self.ts1), {'TagSet': tag.TagSet, 'Tag': tag.Tag}) == self.ts1, 'repr() fails' + class TagSetCmpTestCase(TagSetTestCaseBase): def testCmp(self): @@ -46,25 +70,27 @@ class TagSetCmpTestCase(TagSetTestCaseBase): def testLen(self): assert len(self.ts1) == len(self.ts2), 'tag length comparation fails' + class TaggingTestSuite(TagSetTestCaseBase): def testImplicitTag(self): t = self.ts1.tagImplicitly( tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 14) - ) + ) assert t == tag.TagSet( tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 12), tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 14) - ), 'implicit tagging went wrong' + ), 'implicit tagging went wrong' def testExplicitTag(self): t = self.ts1.tagExplicitly( tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 32) - ) + ) assert t == tag.TagSet( tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), tag.Tag(tag.tagClassPrivate, tag.tagFormatConstructed, 32) - ), 'explicit tagging went wrong' + ), 'explicit tagging went wrong' + class TagSetAddTestSuite(TagSetTestCaseBase): def testAdd(self): @@ -73,7 +99,7 @@ class TagSetAddTestSuite(TagSetTestCaseBase): tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2) - ), 'TagSet.__add__() fails' + ), 'TagSet.__add__() fails' def testRadd(self): t = tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2) + self.ts1 @@ -81,27 +107,32 @@ class TagSetAddTestSuite(TagSetTestCaseBase): tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2), tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) - ), 'TagSet.__radd__() fails' + ), 'TagSet.__radd__() fails' + class SuperTagSetTestCase(TagSetTestCaseBase): def testSuperTagCheck1(self): assert self.ts1.isSuperTagSetOf( tag.TagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) )), 'isSuperTagSetOf() fails' def testSuperTagCheck2(self): assert not self.ts1.isSuperTagSetOf( tag.TagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 13) + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 13) )), 'isSuperTagSetOf() fails' def testSuperTagCheck3(self): assert self.ts1.isSuperTagSetOf( tag.TagSet((), tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)) - ), 'isSuperTagSetOf() fails' - -if __name__ == '__main__': unittest.main() + ), 'isSuperTagSetOf() fails' + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/type/test_univ.py b/third_party/python/pyasn1/tests/type/test_univ.py new file mode 100644 index 000000000000..f5124df2cebc --- /dev/null +++ b/third_party/python/pyasn1/tests/type/test_univ.py @@ -0,0 +1,1503 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys +import math + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import univ, tag, constraint, namedtype, namedval, error +from pyasn1.compat.octets import str2octs, ints2octs, octs2ints +from pyasn1.error import PyAsn1Error + + +class NoValueTestCase(BaseTestCase): + def testSingleton(self): + assert univ.NoValue() is univ.NoValue(), 'NoValue is not a singleton' + + def testRepr(self): + try: + repr(univ.noValue) + + except PyAsn1Error: + assert False, 'repr() on NoValue object fails' + + def testIsInstance(self): + try: + assert isinstance(univ.noValue, univ.NoValue), 'isinstance() on NoValue() object fails' + + except PyAsn1Error: + assert False, 'isinstance() on NoValue object fails' + + def testStr(self): + try: + str(univ.noValue) + + except PyAsn1Error: + pass + + else: + assert False, 'str() works for NoValue object' + + def testLen(self): + try: + len(univ.noValue) + + except PyAsn1Error: + pass + + else: + assert False, 'len() works for NoValue object' + + def testCmp(self): + try: + univ.noValue == 1 + + except PyAsn1Error: + pass + + else: + assert False, 'comparison works for NoValue object' + + def testSubs(self): + try: + univ.noValue[0] + + except PyAsn1Error: + pass + + else: + assert False, '__getitem__() works for NoValue object' + + def testKey(self): + try: + univ.noValue['key'] + + except PyAsn1Error: + pass + + else: + assert False, '__getitem__() works for NoValue object' + + def testKeyAssignment(self): + try: + univ.noValue['key'] = 123 + + except PyAsn1Error: + pass + + else: + assert False, '__setitem__() works for NoValue object' + + def testInt(self): + try: + int(univ.noValue) + + except PyAsn1Error: + pass + + else: + assert False, 'integer conversion works for NoValue object' + + def testAdd(self): + try: + univ.noValue + univ.noValue + + except PyAsn1Error: + pass + + else: + assert False, 'addition works for NoValue object' + + def testBitShift(self): + try: + univ.noValue << 1 + + except PyAsn1Error: + pass + + else: + assert False, 'bitshift works for NoValue object' + + def testBooleanEvaluation(self): + try: + if univ.noValue: + pass + + except PyAsn1Error: + pass + + else: + assert False, 'boolean evaluation works for NoValue object' + + def testSizeOf(self): + try: + if hasattr(sys, 'getsizeof'): + sys.getsizeof(univ.noValue) + + except PyAsn1Error: + assert False, 'sizeof failed for NoValue object' + + +class IntegerTestCase(BaseTestCase): + def testStr(self): + assert str(univ.Integer(1)) in ('1', '1L'), 'str() fails' + + def testRepr(self): + assert eval(repr(univ.Integer(123)), {'Integer': univ.Integer}) == univ.Integer(123), 'repr() fails' + + def testAnd(self): + assert univ.Integer(1) & 0 == 0, '__and__() fails' + + def testOr(self): + assert univ.Integer(1) | 0 == 1, '__or__() fails' + + def testXor(self): + assert univ.Integer(1) ^ 0 == 1, '__xor__() fails' + + def testRand(self): + assert 0 & univ.Integer(1) == 0, '__rand__() fails' + + def testRor(self): + assert 0 | univ.Integer(1) == 1, '__ror__() fails' + + def testRxor(self): + assert 0 ^ univ.Integer(1) == 1, '__rxor__() fails' + + def testAdd(self): + assert univ.Integer(-4) + 6 == 2, '__add__() fails' + + def testRadd(self): + assert 4 + univ.Integer(5) == 9, '__radd__() fails' + + def testSub(self): + assert univ.Integer(3) - 6 == -3, '__sub__() fails' + + def testRsub(self): + assert 6 - univ.Integer(3) == 3, '__rsub__() fails' + + def testMul(self): + assert univ.Integer(3) * -3 == -9, '__mul__() fails' + + def testRmul(self): + assert 2 * univ.Integer(3) == 6, '__rmul__() fails' + + def testDivInt(self): + assert univ.Integer(4) / 2 == 2, '__div__() fails' + + if sys.version_info[0] > 2: + def testDivFloat(self): + assert univ.Integer(3) / 2 == 1.5, '__div__() fails' + + def testRdivFloat(self): + assert 3 / univ.Integer(2) == 1.5, '__rdiv__() fails' + else: + def testDivFloat(self): + assert univ.Integer(3) / 2 == 1, '__div__() fails' + + def testRdivFloat(self): + assert 3 / univ.Integer(2) == 1, '__rdiv__() fails' + + def testRdivInt(self): + assert 6 / univ.Integer(3) == 2, '__rdiv__() fails' + + if sys.version_info[0] > 2: + def testTrueDiv(self): + assert univ.Integer(3) / univ.Integer(2) == 1.5, '__truediv__() fails' + + def testFloorDiv(self): + assert univ.Integer(3) // univ.Integer(2) == 1, '__floordiv__() fails' + + def testMod(self): + assert univ.Integer(3) % 2 == 1, '__mod__() fails' + + def testRmod(self): + assert 4 % univ.Integer(3) == 1, '__rmod__() fails' + + def testPow(self): + assert univ.Integer(3) ** 2 == 9, '__pow__() fails' + + def testRpow(self): + assert 2 ** univ.Integer(2) == 4, '__rpow__() fails' + + def testLshift(self): + assert univ.Integer(1) << 1 == 2, '<< fails' + + def testRshift(self): + assert univ.Integer(2) >> 1 == 1, '>> fails' + + def testInt(self): + assert int(univ.Integer(3)) == 3, '__int__() fails' + + def testLong(self): + assert int(univ.Integer(8)) == 8, '__long__() fails' + + def testFloat(self): + assert float(univ.Integer(4)) == 4.0, '__float__() fails' + + def testPos(self): + assert +univ.Integer(1) == 1, '__pos__() fails' + + def testNeg(self): + assert -univ.Integer(1) == -1, '__neg__() fails' + + def testInvert(self): + assert ~univ.Integer(1) == -2, '__invert__() fails' + + def testRound(self): + assert round(univ.Integer(1), 3) == 1.0, '__round__() fails' + + def testFloor(self): + assert math.floor(univ.Integer(1)) == 1, '__floor__() fails' + + def testCeil(self): + assert math.ceil(univ.Integer(1)) == 1, '__ceil__() fails' + + if sys.version_info[0:2] > (2, 5): + def testTrunc(self): + assert math.trunc(univ.Integer(1)) == 1, '__trunc__() fails' + + def testPrettyIn(self): + assert univ.Integer('3') == 3, 'prettyIn() fails' + + def testTag(self): + assert univ.Integer().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) + ) + + def testNamedVals(self): + + class Integer(univ.Integer): + namedValues = univ.Integer.namedValues.clone(('asn1', 1)) + + assert Integer('asn1') == 1, 'named val fails' + assert str(Integer('asn1')) != 'asn1', 'named val __str__() fails' + + def testSubtype(self): + assert univ.Integer().subtype( + value=1, + implicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 2), + subtypeSpec=constraint.SingleValueConstraint(1, 3) + ) == univ.Integer( + value=1, + tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate, + tag.tagFormatSimple, 2)), + subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1, 3)) + ) + + +class BooleanTestCase(BaseTestCase): + def testTruth(self): + assert univ.Boolean(True) and univ.Boolean(1), 'Truth initializer fails' + + def testFalse(self): + assert not univ.Boolean(False) and not univ.Boolean(0), 'False initializer fails' + + def testStr(self): + assert str(univ.Boolean(1)) in ('1', '1L'), 'str() fails' + + def testRepr(self): + assert eval(repr(univ.Boolean(1)), {'Boolean': univ.Boolean}) == univ.Boolean(1), 'repr() fails' + + def testTag(self): + assert univ.Boolean().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01) + ) + + def testConstraints(self): + + class Boolean(univ.Boolean): + pass + + try: + Boolean(2) + except error.ValueConstraintError: + pass + else: + assert 0, 'constraint fail' + + +class BitStringTestCase(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.b = univ.BitString( + namedValues=namedval.NamedValues(('Active', 0), ('Urgent', 1)) + ) + + def testBinDefault(self): + + class BinDefault(univ.BitString): + defaultBinValue = '1010100110001010' + + assert BinDefault() == univ.BitString(binValue='1010100110001010') + + def testHexDefault(self): + + class HexDefault(univ.BitString): + defaultHexValue = 'A98A' + + assert HexDefault() == univ.BitString(hexValue='A98A') + + def testSet(self): + assert self.b.clone('Active') == (1,) + assert self.b.clone('Urgent') == (0, 1) + assert self.b.clone('Urgent, Active') == (1, 1) + assert self.b.clone("'1010100110001010'B") == (1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0) + assert self.b.clone("'A98A'H") == (1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0) + assert self.b.clone(binValue='1010100110001010') == (1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0) + assert self.b.clone(hexValue='A98A') == (1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0) + assert self.b.clone('1010100110001010') == (1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0) + assert self.b.clone((1, 0, 1)) == (1, 0, 1) + + def testStr(self): + assert str(self.b.clone('Urgent')) == '01' + + def testRepr(self): + assert eval(repr(self.b.clone('Urgent,Active')), {'BitString': univ.BitString}) == self.b.clone( + 'Urgent,Active'), 'repr() fails' + + def testTag(self): + assert univ.BitString().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) + ) + + def testLen(self): + assert len(self.b.clone("'A98A'H")) == 16 + + def testGetItem(self): + assert self.b.clone("'A98A'H")[0] == 1 + assert self.b.clone("'A98A'H")[1] == 0 + assert self.b.clone("'A98A'H")[2] == 1 + + if sys.version_info[:2] > (2, 4): + def testReverse(self): + assert list(reversed(univ.BitString([0, 0, 1]))) == list(univ.BitString([1, 0, 0])) + + def testAsOctets(self): + assert self.b.clone(hexValue='A98A').asOctets() == ints2octs((0xa9, 0x8a)), 'testAsOctets() fails' + + def testAsInts(self): + assert self.b.clone(hexValue='A98A').asNumbers() == (0xa9, 0x8a), 'testAsNumbers() fails' + + def testMultipleOfEightPadding(self): + assert self.b.clone((1, 0, 1)).asNumbers() == (5,) + + def testAsInteger(self): + assert self.b.clone('11000000011001').asInteger() == 12313 + assert self.b.clone('1100110011011111').asInteger() == 52447 + + def testStaticDef(self): + + class BitString(univ.BitString): + pass + + assert BitString('11000000011001').asInteger() == 12313 + + +class OctetStringWithUnicodeMixIn(object): + + initializer = () + encoding = 'us-ascii' + + def setUp(self): + self.pythonString = ints2octs(self.initializer).decode(self.encoding) + self.encodedPythonString = self.pythonString.encode(self.encoding) + self.numbersString = tuple(octs2ints(self.encodedPythonString)) + + def testInit(self): + assert univ.OctetString(self.encodedPythonString) == self.encodedPythonString, '__init__() fails' + + def testInitFromAsn1(self): + assert univ.OctetString(univ.OctetString(self.encodedPythonString)) == self.encodedPythonString + assert univ.OctetString(univ.Integer(123)) == univ.OctetString('123') + + def testSerialized(self): + if sys.version_info[0] < 3: + assert str(univ.OctetString(self.encodedPythonString, encoding=self.encoding)) == self.encodedPythonString, '__str__() fails' + else: + assert bytes(univ.OctetString(self.encodedPythonString, encoding=self.encoding)) == self.encodedPythonString, '__str__() fails' + + def testPrintable(self): + if sys.version_info[0] < 3: + assert str(univ.OctetString(self.encodedPythonString, encoding=self.encoding)) == self.encodedPythonString, '__str__() fails' + assert unicode(univ.OctetString(self.pythonString, encoding=self.encoding)) == self.pythonString, 'unicode init fails' + else: + assert str(univ.OctetString(self.pythonString, encoding=self.encoding)) == self.pythonString, 'unicode init fails' + + def testSeq(self): + assert univ.OctetString(self.encodedPythonString)[0] == self.encodedPythonString[0], '__getitem__() fails' + + def testRepr(self): + assert eval(repr(univ.OctetString('abc')), {'OctetString': univ.OctetString}) == univ.OctetString('abc'), 'repr() fails' + + def testAsOctets(self): + assert univ.OctetString(self.encodedPythonString).asOctets() == self.encodedPythonString, 'testAsOctets() fails' + + def testAsInts(self): + assert univ.OctetString(self.encodedPythonString).asNumbers() == self.numbersString, 'testAsNumbers() fails' + + def testAdd(self): + assert univ.OctetString(self.encodedPythonString) + self.encodedPythonString == self.encodedPythonString + self.encodedPythonString, '__add__() fails' + + def testRadd(self): + assert self.encodedPythonString + univ.OctetString(self.encodedPythonString) == self.encodedPythonString + self.encodedPythonString, '__radd__() fails' + + def testMul(self): + assert univ.OctetString(self.encodedPythonString) * 2 == self.encodedPythonString * 2, '__mul__() fails' + + def testRmul(self): + assert 2 * univ.OctetString(self.encodedPythonString) == 2 * self.encodedPythonString, '__rmul__() fails' + + def testContains(self): + s = univ.OctetString(self.encodedPythonString) + assert self.encodedPythonString in s + assert self.encodedPythonString * 2 not in s + + if sys.version_info[:2] > (2, 4): + def testReverse(self): + assert list(reversed(univ.OctetString(self.encodedPythonString))) == list(reversed(self.encodedPythonString)) + + +class OctetStringWithAsciiTestCase(OctetStringWithUnicodeMixIn, BaseTestCase): + initializer = (97, 102) + encoding = 'us-ascii' + + +class OctetStringWithUtf8TestCase(OctetStringWithUnicodeMixIn, BaseTestCase): + initializer = (208, 176, 208, 177, 208, 178) + encoding = 'utf-8' + + +class OctetStringWithUtf16TestCase(OctetStringWithUnicodeMixIn, BaseTestCase): + initializer = (4, 48, 4, 49, 4, 50) + encoding = 'utf-16-be' + + +if sys.version_info[0] > 2: + + # Somehow comparison of UTF-32 encoded strings does not work in Py2 + + class OctetStringWithUtf32TestCase(OctetStringWithUnicodeMixIn, BaseTestCase): + initializer = (0, 0, 4, 48, 0, 0, 4, 49, 0, 0, 4, 50) + encoding = 'utf-32-be' + + +class OctetStringTestCase(BaseTestCase): + + def testBinDefault(self): + + class BinDefault(univ.OctetString): + defaultBinValue = '1000010111101110101111000000111011' + + assert BinDefault() == univ.OctetString(binValue='1000010111101110101111000000111011') + + def testHexDefault(self): + + class HexDefault(univ.OctetString): + defaultHexValue = 'FA9823C43E43510DE3422' + + assert HexDefault() == univ.OctetString(hexValue='FA9823C43E43510DE3422') + + def testBinStr(self): + assert univ.OctetString(binValue="1000010111101110101111000000111011") == ints2octs((133, 238, 188, 14, 192)), 'bin init fails' + + def testHexStr(self): + assert univ.OctetString(hexValue="FA9823C43E43510DE3422") == ints2octs((250, 152, 35, 196, 62, 67, 81, 13, 227, 66, 32)), 'hex init fails' + + def testTuple(self): + assert univ.OctetString((1, 2, 3, 4, 5)) == ints2octs((1, 2, 3, 4, 5)), 'tuple init failed' + + def testRepr(self): + assert eval(repr(univ.OctetString('abc')), {'OctetString': univ.OctetString}) == univ.OctetString('abc'), 'repr() fails' + + def testEmpty(self): + try: + str(univ.OctetString()) + except PyAsn1Error: + pass + else: + assert 0, 'empty OctetString() not reported' + + def testTag(self): + assert univ.OctetString().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) + ) + + def testStaticDef(self): + + class OctetString(univ.OctetString): + pass + + assert OctetString(hexValue="FA9823C43E43510DE3422") == ints2octs((250, 152, 35, 196, 62, 67, 81, 13, 227, 66, 32)) + + +class Null(BaseTestCase): + def testStr(self): + assert str(univ.Null('')) == '', 'str() fails' + + def testRepr(self): + assert eval(repr(univ.Null()), {'Null': univ.Null}) == univ.Null(), 'repr() fails' + + def testTag(self): + assert univ.Null().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) + ) + + def testConstraints(self): + try: + univ.Null(2) + except error.ValueConstraintError: + pass + else: + assert 0, 'constraint fail' + + def testStaticDef(self): + + class Null(univ.Null): + pass + + assert not Null() + + +class RealTestCase(BaseTestCase): + def testFloat4BinEnc(self): + assert univ.Real((0.25, 2, 3)) == 2.0, 'float initializer for binary encoding fails' + + def testStr(self): + assert str(univ.Real(1.0)) == '1.0', 'str() fails' + + def testRepr(self): + assert eval(repr(univ.Real(-4.1)), {'Real': univ.Real}) == univ.Real(-4.1), 'repr() fails' + assert repr(univ.Real(-4.1)) == 'Real((-41, 10, -1))', 'repr() fails' + assert eval(repr(univ.Real('inf')), {'Real': univ.Real}) == univ.Real('inf'), 'repr() fails' + assert repr(univ.Real('inf')) == 'Real(\'inf\')', 'repr() fails' + + def testAdd(self): + assert univ.Real(-4.1) + 1.4 == -2.7, '__add__() fails' + + def testRadd(self): + assert 4 + univ.Real(0.5) == 4.5, '__radd__() fails' + + def testSub(self): + assert univ.Real(3.9) - 1.7 == 2.2, '__sub__() fails' + + def testRsub(self): + assert 6.1 - univ.Real(0.1) == 6, '__rsub__() fails' + + def testMul(self): + assert univ.Real(3.0) * -3 == -9, '__mul__() fails' + + def testRmul(self): + assert 2 * univ.Real(3.0) == 6, '__rmul__() fails' + + def testDiv(self): + assert univ.Real(3.0) / 2 == 1.5, '__div__() fails' + + def testRdiv(self): + assert 6 / univ.Real(3.0) == 2, '__rdiv__() fails' + + def testMod(self): + assert univ.Real(3.0) % 2 == 1, '__mod__() fails' + + def testRmod(self): + assert 4 % univ.Real(3.0) == 1, '__rmod__() fails' + + def testPow(self): + assert univ.Real(3.0) ** 2 == 9, '__pow__() fails' + + def testRpow(self): + assert 2 ** univ.Real(2.0) == 4, '__rpow__() fails' + + def testInt(self): + assert int(univ.Real(3.0)) == 3, '__int__() fails' + + def testLong(self): + assert int(univ.Real(8.0)) == 8, '__long__() fails' + + def testFloat(self): + assert float(univ.Real(4.0)) == 4.0, '__float__() fails' + + def testPrettyIn(self): + assert univ.Real((3, 10, 0)) == 3, 'prettyIn() fails' + + # infinite float values + def testStrInf(self): + assert str(univ.Real('inf')) == 'inf', 'str() fails' + + def testAddInf(self): + assert univ.Real('inf') + 1 == float('inf'), '__add__() fails' + + def testRaddInf(self): + assert 1 + univ.Real('inf') == float('inf'), '__radd__() fails' + + def testIntInf(self): + try: + assert int(univ.Real('inf')) + except OverflowError: + pass + else: + assert 0, '__int__() fails' + + def testLongInf(self): + try: + assert int(univ.Real('inf')) + except OverflowError: + pass + else: + assert 0, '__long__() fails' + assert int(univ.Real(8.0)) == 8, '__long__() fails' + + def testFloatInf(self): + assert float(univ.Real('-inf')) == float('-inf'), '__float__() fails' + + def testPrettyInInf(self): + assert univ.Real(float('inf')) == float('inf'), 'prettyIn() fails' + + def testPlusInf(self): + assert univ.Real('inf').isPlusInf, 'isPlusInfinity failed' + + def testMinusInf(self): + assert univ.Real('-inf').isMinusInf, 'isMinusInfinity failed' + + def testPos(self): + assert +univ.Real(1.0) == 1.0, '__pos__() fails' + + def testNeg(self): + assert -univ.Real(1.0) == -1.0, '__neg__() fails' + + def testRound(self): + assert round(univ.Real(1.123), 2) == 1.12, '__round__() fails' + + def testFloor(self): + assert math.floor(univ.Real(1.6)) == 1.0, '__floor__() fails' + + def testCeil(self): + assert math.ceil(univ.Real(1.2)) == 2.0, '__ceil__() fails' + + if sys.version_info[0:2] > (2, 5): + def testTrunc(self): + assert math.trunc(univ.Real(1.1)) == 1.0, '__trunc__() fails' + + def testTag(self): + assert univ.Real().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) + ) + + def testStaticDef(self): + + class Real(univ.Real): + pass + + assert Real(1.0) == 1.0 + + +class ObjectIdentifier(BaseTestCase): + def testStr(self): + assert str(univ.ObjectIdentifier((1, 3, 6))) == '1.3.6', 'str() fails' + + def testRepr(self): + assert eval(repr(univ.ObjectIdentifier('1.3.6')), + {'ObjectIdentifier': univ.ObjectIdentifier}) == univ.ObjectIdentifier('1.3.6'), 'repr() fails' + + def testEq(self): + assert univ.ObjectIdentifier((1, 3, 6)) == (1, 3, 6), '__cmp__() fails' + + def testAdd(self): + assert univ.ObjectIdentifier((1, 3)) + (6,) == (1, 3, 6), '__add__() fails' + + def testRadd(self): + assert (1,) + univ.ObjectIdentifier((3, 6)) == (1, 3, 6), '__radd__() fails' + + def testLen(self): + assert len(univ.ObjectIdentifier((1, 3))) == 2, '__len__() fails' + + def testPrefix(self): + o = univ.ObjectIdentifier('1.3.6') + assert o.isPrefixOf((1, 3, 6)), 'isPrefixOf() fails' + assert o.isPrefixOf((1, 3, 6, 1)), 'isPrefixOf() fails' + assert not o.isPrefixOf((1, 3)), 'isPrefixOf() fails' + + def testInput1(self): + assert univ.ObjectIdentifier('1.3.6') == (1, 3, 6), 'prettyIn() fails' + + def testInput2(self): + assert univ.ObjectIdentifier((1, 3, 6)) == (1, 3, 6), 'prettyIn() fails' + + def testInput3(self): + assert univ.ObjectIdentifier(univ.ObjectIdentifier('1.3') + (6,)) == (1, 3, 6), 'prettyIn() fails' + + def testUnicode(self): + s = '1.3.6' + if sys.version_info[0] < 3: + s = s.decode() + assert univ.ObjectIdentifier(s) == (1, 3, 6), 'unicode init fails' + + def testTag(self): + assert univ.ObjectIdentifier().tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) + ) + + def testContains(self): + s = univ.ObjectIdentifier('1.3.6.1234.99999') + assert 1234 in s + assert 4321 not in s + + def testStaticDef(self): + + class ObjectIdentifier(univ.ObjectIdentifier): + pass + + assert str(ObjectIdentifier((1, 3, 6))) == '1.3.6' + + +class SequenceOf(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s1 = univ.SequenceOf( + componentType=univ.OctetString('') + ) + self.s2 = self.s1.clone() + + def testRepr(self): + assert eval(repr(self.s1.clone().setComponents('a', 'b')), + {'SequenceOf': univ.SequenceOf, + 'OctetString': univ.OctetString}) == self.s1.clone().setComponents( + 'a', 'b'), 'repr() fails' + + def testTag(self): + assert self.s1.tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ), 'wrong tagSet' + + def testSeq(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + assert self.s1[0] == str2octs('abc'), 'set by idx fails' + self.s1[0] = 'cba' + assert self.s1[0] == str2octs('cba'), 'set by idx fails' + + def testCmp(self): + self.s1.clear() + self.s1.setComponentByPosition(0, 'abc') + self.s2.clear() + self.s2.setComponentByPosition(0, univ.OctetString('abc')) + assert self.s1 == self.s2, '__cmp__() fails' + + def testSubtypeSpec(self): + s = self.s1.clone(subtypeSpec=constraint.ConstraintsUnion( + constraint.SingleValueConstraint(str2octs('abc')) + )) + try: + s.setComponentByPosition(0, univ.OctetString('abc')) + except PyAsn1Error: + assert 0, 'constraint fails' + try: + s.setComponentByPosition(1, univ.OctetString('Abc')) + except PyAsn1Error: + try: + s.setComponentByPosition(1, univ.OctetString('Abc'), + verifyConstraints=False) + except PyAsn1Error: + assert 0, 'constraint failes with verifyConstraints=True' + else: + assert 0, 'constraint fails' + + def testComponentTagsMatching(self): + s = self.s1.clone() + s.strictConstraints = True # This requires types equality + o = univ.OctetString('abc').subtype(explicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 12)) + try: + s.setComponentByPosition(0, o) + except PyAsn1Error: + pass + else: + assert 0, 'inner supertype tag allowed' + + def testComponentConstraintsMatching(self): + s = self.s1.clone() + o = univ.OctetString().subtype( + subtypeSpec=constraint.ConstraintsUnion(constraint.SingleValueConstraint(str2octs('cba')))) + s.strictConstraints = True # This requires types equality + try: + s.setComponentByPosition(0, o.clone('cba')) + except PyAsn1Error: + pass + else: + assert 0, 'inner supertype constraint allowed' + s.strictConstraints = False # This requires subtype relationships + try: + s.setComponentByPosition(0, o.clone('cba')) + except PyAsn1Error: + assert 0, 'inner supertype constraint disallowed' + else: + pass + + def testSizeSpec(self): + s = self.s1.clone(sizeSpec=constraint.ConstraintsUnion( + constraint.ValueSizeConstraint(1, 1) + )) + s.setComponentByPosition(0, univ.OctetString('abc')) + try: + s.verifySizeSpec() + except PyAsn1Error: + assert 0, 'size spec fails' + s.setComponentByPosition(1, univ.OctetString('abc')) + try: + s.verifySizeSpec() + except PyAsn1Error: + pass + else: + assert 0, 'size spec fails' + + def testGetComponentTagMap(self): + assert self.s1.componentType.tagMap.presentTypes == { + univ.OctetString.tagSet: univ.OctetString('') + } + + def testSubtype(self): + self.s1.clear() + assert self.s1.subtype( + implicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 2), + subtypeSpec=constraint.SingleValueConstraint(1, 3), + sizeSpec=constraint.ValueSizeConstraint(0, 1) + ) == self.s1.clone( + tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate, + tag.tagFormatSimple, 2)), + subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1, 3)), + sizeSpec=constraint.ValueSizeConstraint(0, 1) + ) + + def testClone(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + s = self.s1.clone() + assert len(s) == 0 + s = self.s1.clone(cloneValueFlag=1) + assert len(s) == 1 + assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0) + + def testSetComponents(self): + assert self.s1.clone().setComponents('abc', 'def') == \ + self.s1.setComponentByPosition(0, 'abc').setComponentByPosition(1, 'def') + + def testGetItem(self): + s = self.s1.clone() + s.append('xxx') + assert s[0] + + try: + s[2] + + except IndexError: + pass + + else: + assert False, 'IndexError not raised' + + # this is a deviation from standart sequence protocol + assert not s[1] + + def testSetItem(self): + s = self.s1.clone() + s.append('xxx') + + try: + + s[2] = 'xxx' + + except IndexError: + pass + + else: + assert False, 'IndexError not raised' + + def testAppend(self): + self.s1.clear() + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + assert len(self.s1) == 1 + self.s1.append('def') + assert len(self.s1) == 2 + assert list(self.s1) == [str2octs(x) for x in ['abc', 'def']] + + def testExtend(self): + self.s1.clear() + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + assert len(self.s1) == 1 + self.s1.extend(['def', 'ghi']) + assert len(self.s1) == 3 + assert list(self.s1) == [str2octs(x) for x in ['abc', 'def', 'ghi']] + + def testCount(self): + self.s1.clear() + for x in ['abc', 'def', 'abc']: + self.s1.append(x) + assert self.s1.count(str2octs('abc')) == 2 + assert self.s1.count(str2octs('def')) == 1 + assert self.s1.count(str2octs('ghi')) == 0 + + def testIndex(self): + self.s1.clear() + for x in ['abc', 'def', 'abc']: + self.s1.append(x) + assert self.s1.index(str2octs('abc')) == 0 + assert self.s1.index(str2octs('def')) == 1 + assert self.s1.index(str2octs('abc'), 1) == 2 + + def testSort(self): + self.s1.clear() + self.s1[0] = 'b' + self.s1[1] = 'a' + assert list(self.s1) == [str2octs('b'), str2octs('a')] + self.s1.sort() + assert list(self.s1) == [str2octs('a'), str2octs('b')] + + def testStaticDef(self): + + class SequenceOf(univ.SequenceOf): + componentType = univ.OctetString('') + + s = SequenceOf() + s[0] = 'abc' + assert len(s) == 1 + assert s == [str2octs('abc')] + + def testLegacyInitializer(self): + n = univ.SequenceOf( + componentType=univ.OctetString() + ) + o = univ.SequenceOf( + univ.OctetString() # this is the old way + ) + + assert n.isSameTypeWith(o) and o.isSameTypeWith(n) + + n[0] = 'fox' + o[0] = 'fox' + + assert n == o + +class Sequence(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s1 = univ.Sequence( + componentType=namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString('')), + namedtype.OptionalNamedType('nick', univ.OctetString('')), + namedtype.DefaultedNamedType('age', univ.Integer(34)) + ) + ) + + def testRepr(self): + assert eval( + repr(self.s1.clone().setComponents('a', 'b')), + {'Sequence': univ.Sequence, + 'OctetString': univ.OctetString, + 'Integer': univ.Integer, + 'NamedTypes': namedtype.NamedTypes, + 'NamedType': namedtype.NamedType, + 'OptionalNamedType': namedtype.OptionalNamedType, + 'DefaultedNamedType': namedtype.DefaultedNamedType} + ) == self.s1.clone().setComponents('a', 'b'), 'repr() fails' + + def testTag(self): + assert self.s1.tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ), 'wrong tagSet' + + def testById(self): + self.s1.setComponentByName('name', univ.OctetString('abc')) + assert self.s1.getComponentByName('name') == str2octs('abc'), 'set by name fails' + + def testByKey(self): + self.s1['name'] = 'abc' + assert self.s1['name'] == str2octs('abc'), 'set by key fails' + + def testContains(self): + assert 'name' in self.s1 + assert '' not in self.s1 + + def testGetNearPosition(self): + assert self.s1.componentType.getTagMapNearPosition(1).presentTypes == { + univ.OctetString.tagSet: univ.OctetString(''), + univ.Integer.tagSet: univ.Integer(34) + } + assert self.s1.componentType.getPositionNearType( + univ.OctetString.tagSet, 1 + ) == 1 + + def testSetDefaultComponents(self): + self.s1.clear() + self.s1.setComponentByPosition(0, univ.OctetString('Ping')) + self.s1.setComponentByPosition(1, univ.OctetString('Pong')) + assert self.s1.getComponentByPosition(2) == 34 + + def testClone(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + self.s1.setComponentByPosition(1, univ.OctetString('def')) + self.s1.setComponentByPosition(2, univ.Integer(123)) + s = self.s1.clone() + assert s.getComponentByPosition(0) != self.s1.getComponentByPosition(0) + assert s.getComponentByPosition(1) != self.s1.getComponentByPosition(1) + assert s.getComponentByPosition(2) != self.s1.getComponentByPosition(2) + s = self.s1.clone(cloneValueFlag=1) + assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0) + assert s.getComponentByPosition(1) == self.s1.getComponentByPosition(1) + assert s.getComponentByPosition(2) == self.s1.getComponentByPosition(2) + + def testComponentTagsMatching(self): + s = self.s1.clone() + s.strictConstraints = True # This requires types equality + o = univ.OctetString('abc').subtype(explicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 12)) + try: + s.setComponentByName('name', o) + except PyAsn1Error: + pass + else: + assert 0, 'inner supertype tag allowed' + + def testComponentConstraintsMatching(self): + s = self.s1.clone() + o = univ.OctetString().subtype( + subtypeSpec=constraint.ConstraintsUnion(constraint.SingleValueConstraint(str2octs('cba')))) + s.strictConstraints = True # This requires types equality + try: + s.setComponentByName('name', o.clone('cba')) + except PyAsn1Error: + pass + else: + assert 0, 'inner supertype constraint allowed' + s.strictConstraints = False # This requires subtype relationships + try: + s.setComponentByName('name', o.clone('cba')) + except PyAsn1Error: + assert 0, 'inner supertype constraint disallowed' + else: + pass + + def testSetComponents(self): + assert self.s1.clone().setComponents(name='a', nick='b', age=1) == \ + self.s1.setComponentByPosition(0, 'a').setComponentByPosition(1, 'b').setComponentByPosition(2, 1) + + def testSetToDefault(self): + s = self.s1.clone() + s.setComponentByPosition(0, univ.noValue) + s[2] = univ.noValue + assert s[0] == univ.OctetString('') + assert s[2] == univ.Integer(34) + + def testGetItem(self): + s = self.s1.clone() + s['name'] = 'xxx' + assert s['name'] + assert s[0] + + try: + s['xxx'] + + except KeyError: + pass + + else: + assert False, 'KeyError not raised' + + try: + s[100] + + except IndexError: + pass + + else: + assert False, 'IndexError not raised' + + def testSetItem(self): + s = self.s1.clone() + s['name'] = 'xxx' + + try: + + s['xxx'] = 'xxx' + + except KeyError: + pass + + else: + assert False, 'KeyError not raised' + + try: + + s[100] = 'xxx' + + except IndexError: + pass + + else: + assert False, 'IndexError not raised' + + def testIter(self): + assert list(self.s1) == ['name', 'nick', 'age'] + + def testKeys(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + self.s1.setComponentByPosition(1, univ.OctetString('def')) + self.s1.setComponentByPosition(2, univ.Integer(123)) + assert list(self.s1.keys()) == ['name', 'nick', 'age'] + + def testValues(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + self.s1.setComponentByPosition(1, univ.OctetString('def')) + self.s1.setComponentByPosition(2, univ.Integer(123)) + assert list(self.s1.values()) == [str2octs('abc'), str2octs('def'), 123] + + def testItems(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + self.s1.setComponentByPosition(1, univ.OctetString('def')) + self.s1.setComponentByPosition(2, univ.Integer(123)) + assert list(self.s1.items()) == [(x[0], str2octs(x[1])) for x in [('name', 'abc'), ('nick', 'def')]] + [('age', 123)] + + def testUpdate(self): + self.s1.clear() + assert list(self.s1.values()) == [str2octs(''), str2octs(''), 34] + self.s1.update(**{'name': 'abc', 'nick': 'def', 'age': 123}) + assert list(self.s1.items()) == [(x[0], str2octs(x[1])) for x in [('name', 'abc'), ('nick', 'def')]] + [('age', 123)] + self.s1.update(('name', 'ABC')) + assert list(self.s1.items()) == [(x[0], str2octs(x[1])) for x in [('name', 'ABC'), ('nick', 'def')]] + [('age', 123)] + self.s1.update(name='CBA') + assert list(self.s1.items()) == [(x[0], str2octs(x[1])) for x in [('name', 'CBA'), ('nick', 'def')]] + [('age', 123)] + + def testStaticDef(self): + + class Sequence(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString('')), + namedtype.OptionalNamedType('nick', univ.OctetString('')), + namedtype.DefaultedNamedType('age', univ.Integer(34)) + ) + + s = Sequence() + s['name'] = 'abc' + assert s['name'] == str2octs('abc') + + +class SequenceWithoutSchema(BaseTestCase): + + def testGetItem(self): + s = univ.Sequence() + s.setComponentByPosition(0, univ.OctetString('abc')) + s[0] = 'abc' + assert s['field-0'] + assert s[0] + + try: + s['field-1'] + + except KeyError: + pass + + else: + assert False, 'KeyError not raised' + + def testSetItem(self): + s = univ.Sequence() + s.setComponentByPosition(0, univ.OctetString('abc')) + s['field-0'] = 'xxx' + + try: + + s['field-1'] = 'xxx' + + except KeyError: + pass + + else: + assert False, 'KeyError not raised' + + def testIter(self): + s = univ.Sequence() + s.setComponentByPosition(0, univ.OctetString('abc')) + s.setComponentByPosition(1, univ.Integer(123)) + assert list(s) == ['field-0', 'field-1'] + + def testKeys(self): + s = univ.Sequence() + s.setComponentByPosition(0, univ.OctetString('abc')) + s.setComponentByPosition(1, univ.Integer(123)) + assert list(s.keys()) == ['field-0', 'field-1'] + + def testValues(self): + s = univ.Sequence() + s.setComponentByPosition(0, univ.OctetString('abc')) + s.setComponentByPosition(1, univ.Integer(123)) + assert list(s.values()) == [str2octs('abc'), 123] + + def testItems(self): + s = univ.Sequence() + s.setComponentByPosition(0, univ.OctetString('abc')) + s.setComponentByPosition(1, univ.Integer(123)) + assert list(s.items()) == [('field-0', str2octs('abc')), ('field-1', 123)] + + def testUpdate(self): + s = univ.Sequence() + assert not s + s.setComponentByPosition(0, univ.OctetString('abc')) + s.setComponentByPosition(1, univ.Integer(123)) + assert s + assert list(s.keys()) == ['field-0', 'field-1'] + assert list(s.values()) == [str2octs('abc'), 123] + assert list(s.items()) == [('field-0', str2octs('abc')), ('field-1', 123)] + s['field-0'] = univ.OctetString('def') + assert list(s.values()) == [str2octs('def'), 123] + s['field-1'] = univ.OctetString('ghi') + assert list(s.values()) == [str2octs('def'), str2octs('ghi')] + try: + s['field-2'] = univ.OctetString('xxx') + except KeyError: + pass + else: + assert False, 'unknown field at schema-less object tolerated' + assert 'field-0' in s + s.clear() + assert 'field-0' not in s + + +class SetOf(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + self.s1 = univ.SetOf(componentType=univ.OctetString('')) + + def testTag(self): + assert self.s1.tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ), 'wrong tagSet' + + def testSeq(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + assert self.s1[0] == str2octs('abc'), 'set by idx fails' + self.s1.setComponentByPosition(0, self.s1[0].clone('cba')) + assert self.s1[0] == str2octs('cba'), 'set by idx fails' + + def testStaticDef(self): + + class SetOf(univ.SequenceOf): + componentType = univ.OctetString('') + + s = SetOf() + s[0] = 'abc' + assert len(s) == 1 + assert s == [str2octs('abc')] + + +class Set(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + self.s1 = univ.Set( + componentType=namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString('')), + namedtype.OptionalNamedType('null', univ.Null('')), + namedtype.DefaultedNamedType('age', univ.Integer(34)) + ) + ) + self.s2 = self.s1.clone() + + def testTag(self): + assert self.s1.tagSet == tag.TagSet( + (), + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ), 'wrong tagSet' + + def testByTypeWithPythonValue(self): + self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') + assert self.s1.getComponentByType( + univ.OctetString.tagSet + ) == str2octs('abc'), 'set by name fails' + + def testByTypeWithInstance(self): + self.s1.setComponentByType(univ.OctetString.tagSet, univ.OctetString('abc')) + assert self.s1.getComponentByType( + univ.OctetString.tagSet + ) == str2octs('abc'), 'set by name fails' + + def testGetTagMap(self): + assert self.s1.tagMap.presentTypes == { + univ.Set.tagSet: univ.Set() + } + + def testGetComponentTagMap(self): + assert self.s1.componentType.tagMapUnique.presentTypes == { + univ.OctetString.tagSet: univ.OctetString(''), + univ.Null.tagSet: univ.Null(''), + univ.Integer.tagSet: univ.Integer(34) + } + + def testGetPositionByType(self): + assert self.s1.componentType.getPositionByType(univ.Null().tagSet) == 1 + + def testSetToDefault(self): + self.s1.setComponentByName('name', univ.noValue) + assert self.s1['name'] == univ.OctetString('') + + def testIter(self): + assert list(self.s1) == ['name', 'null', 'age'] + + def testStaticDef(self): + + class Set(univ.Set): + componentType = namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString('')), + namedtype.OptionalNamedType('nick', univ.OctetString('')), + namedtype.DefaultedNamedType('age', univ.Integer(34)) + ) + + s = Set() + s['name'] = 'abc' + assert s['name'] == str2octs('abc') + + +class Choice(BaseTestCase): + def setUp(self): + BaseTestCase.setUp(self) + + innerComp = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('count', univ.Integer()), + namedtype.NamedType('flag', univ.Boolean()) + ) + ) + self.s1 = univ.Choice( + componentType=namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString()), + namedtype.NamedType('sex', innerComp) + ) + ) + + def testTag(self): + assert self.s1.tagSet == tag.TagSet(), 'wrong tagSet' + + def testRepr(self): + assert eval(repr(self.s1.clone().setComponents('a')), + {'Choice': univ.Choice, 'OctetString': univ.OctetString, 'Integer': univ.Integer, + 'Boolean': univ.Boolean, 'NamedTypes': namedtype.NamedTypes, + 'NamedType': namedtype.NamedType}) == self.s1.clone().setComponents('a'), 'repr() fails' + assert eval(repr(self.s1.clone().setComponents( + sex=self.s1.setComponentByPosition(1).getComponentByPosition(1).clone().setComponents( + count=univ.Integer(123)))), + {'Choice': univ.Choice, 'OctetString': univ.OctetString, 'Integer': univ.Integer, + 'Boolean': univ.Boolean, 'NamedTypes': namedtype.NamedTypes, + 'NamedType': namedtype.NamedType}) == self.s1.clone().setComponents( + sex=self.s1.setComponentByPosition(1).getComponentByPosition(1).clone().setComponents( + count=univ.Integer(123))), 'repr() fails' + + def testContains(self): + self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') + assert 'name' in self.s1 + assert 'sex' not in self.s1 + + self.s1.setComponentByType(univ.Integer.tagSet, 123, innerFlag=True) + assert 'name' not in self.s1 + assert 'sex' in self.s1 + + def testIter(self): + self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') + assert list(self.s1) == ['name'] + self.s1.setComponentByType(univ.Integer.tagSet, 123, innerFlag=True) + assert list(self.s1) == ['sex'] + + def testOuterByTypeWithPythonValue(self): + self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') + assert self.s1.getComponentByType( + univ.OctetString.tagSet + ) == str2octs('abc') + + def testOuterByTypeWithInstanceValue(self): + self.s1.setComponentByType( + univ.OctetString.tagSet, univ.OctetString('abc') + ) + assert self.s1.getComponentByType( + univ.OctetString.tagSet + ) == str2octs('abc') + + def testInnerByTypeWithPythonValue(self): + self.s1.setComponentByType(univ.Integer.tagSet, 123, innerFlag=True) + assert self.s1.getComponentByType( + univ.Integer.tagSet, 1 + ) == 123 + + def testInnerByTypeWithInstanceValue(self): + self.s1.setComponentByType( + univ.Integer.tagSet, univ.Integer(123), innerFlag=True + ) + assert self.s1.getComponentByType( + univ.Integer.tagSet, 1 + ) == 123 + + def testCmp(self): + self.s1.setComponentByName('name', univ.OctetString('abc')) + assert self.s1 == str2octs('abc'), '__cmp__() fails' + + def testGetComponent(self): + self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') + assert self.s1.getComponent() == str2octs('abc'), 'getComponent() fails' + + def testGetName(self): + self.s1.setComponentByType(univ.OctetString.tagSet, 'abc') + assert self.s1.getName() == 'name', 'getName() fails' + + def testSetComponentByPosition(self): + self.s1.setComponentByPosition(0, univ.OctetString('Jim')) + assert self.s1 == str2octs('Jim') + + def testClone(self): + self.s1.setComponentByPosition(0, univ.OctetString('abc')) + s = self.s1.clone() + assert len(s) == 0 + s = self.s1.clone(cloneValueFlag=1) + assert len(s) == 1 + assert s.getComponentByPosition(0) == self.s1.getComponentByPosition(0) + + def testSetToDefault(self): + s = self.s1.clone() + s.setComponentByName('sex', univ.noValue) + assert s['sex'] is not univ.noValue + + def testStaticDef(self): + + class InnerChoice(univ.Choice): + componentType = namedtype.NamedTypes( + namedtype.NamedType('count', univ.Integer()), + namedtype.NamedType('flag', univ.Boolean()) + ) + + class OuterChoice(univ.Choice): + componentType = namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString()), + namedtype.NamedType('sex', InnerChoice()) + ) + + c = OuterChoice() + + c.setComponentByType(univ.OctetString.tagSet, 'abc') + assert c.getName() == 'name' + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/third_party/python/pyasn1/tests/type/test_useful.py b/third_party/python/pyasn1/tests/type/test_useful.py new file mode 100644 index 000000000000..82a97d7e48da --- /dev/null +++ b/third_party/python/pyasn1/tests/type/test_useful.py @@ -0,0 +1,104 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2017, Ilya Etingof +# License: http://pyasn1.sf.net/license.html +# +import sys +import datetime +from copy import deepcopy + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from tests.base import BaseTestCase + +from pyasn1.type import useful + +class FixedOffset(datetime.tzinfo): + def __init__(self, offset, name): + self.__offset = datetime.timedelta(minutes=offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return datetime.timedelta(0) + + +UTC = FixedOffset(0, 'UTC') +UTC2 = FixedOffset(120, 'UTC') + + +class ObjectDescriptorTestCase(BaseTestCase): + pass + + +class GeneralizedTimeTestCase(BaseTestCase): + + def testFromDateTime(self): + assert useful.GeneralizedTime.fromDateTime(datetime.datetime(2017, 7, 11, 0, 1, 2, 30000, tzinfo=UTC)) == '20170711000102.3Z' + + def testToDateTime0(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2) == useful.GeneralizedTime('20170711000102').asDateTime + + def testToDateTime1(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, tzinfo=UTC) == useful.GeneralizedTime('20170711000102Z').asDateTime + + def testToDateTime2(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, 30000, tzinfo=UTC) == useful.GeneralizedTime('20170711000102.3Z').asDateTime + + def testToDateTime3(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, 30000, tzinfo=UTC) == useful.GeneralizedTime('20170711000102,3Z').asDateTime + + def testToDateTime4(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, 30000, tzinfo=UTC) == useful.GeneralizedTime('20170711000102.3+0000').asDateTime + + def testToDateTime5(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, 30000, tzinfo=UTC2) == useful.GeneralizedTime('20170711000102.3+0200').asDateTime + + def testToDateTime6(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, 30000, tzinfo=UTC2) == useful.GeneralizedTime('20170711000102.3+02').asDateTime + + def testToDateTime7(self): + assert datetime.datetime(2017, 7, 11, 0, 1) == useful.GeneralizedTime('201707110001').asDateTime + + def testToDateTime8(self): + assert datetime.datetime(2017, 7, 11, 0) == useful.GeneralizedTime('2017071100').asDateTime + + def testCopy(self): + dt = useful.GeneralizedTime("20170916234254+0130").asDateTime + assert dt == deepcopy(dt) + + +class UTCTimeTestCase(BaseTestCase): + + def testFromDateTime(self): + assert useful.UTCTime.fromDateTime(datetime.datetime(2017, 7, 11, 0, 1, 2, tzinfo=UTC)) == '170711000102Z' + + def testToDateTime0(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2) == useful.UTCTime('170711000102').asDateTime + + def testToDateTime1(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, tzinfo=UTC) == useful.UTCTime('170711000102Z').asDateTime + + def testToDateTime2(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, tzinfo=UTC) == useful.UTCTime('170711000102+0000').asDateTime + + def testToDateTime3(self): + assert datetime.datetime(2017, 7, 11, 0, 1, 2, tzinfo=UTC2) == useful.UTCTime('170711000102+0200').asDateTime + + def testToDateTime4(self): + assert datetime.datetime(2017, 7, 11, 0, 1) == useful.UTCTime('1707110001').asDateTime + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite)