______________________________
Sometimes you either can not or do not want to explicitly set *defines*
-in the scheme. You can dynamically apply those definitions when calling
+in the schema. You can dynamically apply those definitions when calling
``.decode()`` method.
Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
Integer
_______
.. autoclass:: pyderasn.Integer
- :members: __init__
+ :members: __init__, named
BitString
_________
.. autoclass:: pyderasn.BitString
- :members: __init__
+ :members: __init__, bit_len, named
OctetString
___________
PrintableString
_______________
.. autoclass:: pyderasn.PrintableString
- :members: __init__
+ :members: __init__, allow_asterisk, allow_ampersand
UTCTime
_______
GeneralizedTime
_______________
.. autoclass:: pyderasn.GeneralizedTime
+ :members: __init__, todatetime
Special types
-------------
Choice
______
.. autoclass:: pyderasn.Choice
- :members: __init__
+ :members: __init__, choice, value
PrimitiveTypes
______________
.. autoclass:: pyderasn.ObjNotReady
.. autoclass:: pyderasn.InvalidValueType
.. autoclass:: pyderasn.BoundsError
+
+.. _cmdline:
+
+Command-line usage
+------------------
+
+You can decode DER/BER files using command line abilities::
+
+ $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
+
+If there is no schema for your file, then you can try parsing it without,
+but of course IMPLICIT tags will often make it impossible. But result is
+good enough for the certificate above::
+
+ $ python -m pyderasn path/to/file
+ 0 [1,3,1604] . >: SEQUENCE OF
+ 4 [1,3,1453] . . >: SEQUENCE OF
+ 8 [0,0, 5] . . . . >: [0] ANY
+ . . . . . A0:03:02:01:02
+ 13 [1,1, 3] . . . . >: INTEGER 61595
+ 18 [1,1, 13] . . . . >: SEQUENCE OF
+ 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
+ 31 [1,1, 0] . . . . . . >: NULL
+ 33 [1,3, 274] . . . . >: SEQUENCE OF
+ 37 [1,1, 11] . . . . . . >: SET OF
+ 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
+ 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
+ 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
+ [...]
+ 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
+ 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
+ 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
+ . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
+ . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
+ . . . . . . . . . 61:2E:63:6F:6D:2F
+ 1461 [1,1, 13] . . >: SEQUENCE OF
+ 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
+ 1474 [1,1, 0] . . . . >: NULL
+ 1476 [1,2, 129] . . >: BIT STRING 1024 bits
+ . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
+ . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
+ [...]
+
+Human readable OIDs
+___________________
+
+If you have got dictionaries with ObjectIdentifiers, like example one
+from ``tests/test_crts.py``::
+
+ stroid2name = {
+ "1.2.840.113549.1.1.1": "id-rsaEncryption",
+ "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
+ [...]
+ "2.5.4.10": "id-at-organizationName",
+ "2.5.4.11": "id-at-organizationalUnitName",
+ }
+
+then you can pass it to pretty printer to see human readable OIDs::
+
+ $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
+ [...]
+ 37 [1,1, 11] . . . . . . >: SET OF
+ 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
+ 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
+ 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
+ 50 [1,1, 18] . . . . . . >: SET OF
+ 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
+ 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
+ 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
+ 70 [1,1, 18] . . . . . . >: SET OF
+ 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
+ 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
+ 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
+ [...]
+
+Decode paths
+____________
+
+Each decoded element has so-called decode path: sequence of structure
+names it is passing during the decode process. Each element has its own
+unique path inside the whole ASN.1 tree. You can print it out with
+``--print-decode-path`` option::
+
+ $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
+ 0 [1,3,1604] Certificate SEQUENCE []
+ 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
+ 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
+ 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
+ 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
+ 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
+ 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
+ . . . . 05:00
+ 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
+ 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
+ 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
+ 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
+ 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
+ 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
+ . . . . . . . 13:02:45:53
+ 46 [1,1, 2] . . . . . . . DEFINED BY 2.5.4.6: CountryName PrintableString ES [tbsCertificate:issuer:rdnSequence:0:0:value:DEFINED BY 2.5.4.6]
+ [...]
+
+Now you can print only the specified tree, for example signature algorithm::
+
+ $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
+ 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
+ 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
+ 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
+ . . 05:00
"""
from codecs import getdecoder
from datetime import datetime
from datetime import timedelta
from math import ceil
-from os import environ
from string import ascii_letters
from string import digits
from sys import version_info
return type.__new__(cls, name, bases, _dict)
+BasicState = namedtuple("BasicState", (
+ "version",
+ "tag",
+ "expl",
+ "default",
+ "optional",
+ "offset",
+ "llen",
+ "vlen",
+ "expl_lenindef",
+ "lenindef",
+ "ber_encoded",
+), **NAMEDTUPLE_KWARGS)
+
+
@add_metaclass(AutoAddSlots)
class Obj(object):
"""Common ASN.1 object class
def __setstate__(self, state):
if state.version != __version__:
raise ValueError("data is pickled by different PyDERASN version")
- self.tag = self.tag_default
- self._value = None
- self._expl = None
- self.default = None
- self.optional = False
- self.offset = 0
- self.llen = 0
- self.vlen = 0
- self.expl_lenindef = False
- self.lenindef = False
- self.ber_encoded = False
+ self.tag = state.tag
+ self._expl = state.expl
+ self.default = state.default
+ self.optional = state.optional
+ self.offset = state.offset
+ self.llen = state.llen
+ self.vlen = state.vlen
+ self.expl_lenindef = state.expl_lenindef
+ self.lenindef = state.lenindef
+ self.ber_encoded = state.ber_encoded
@property
def tlen(self):
:param ctx: optional :ref:`context <ctx>` governing decoding process
:param tag_only: decode only the tag, without length and contents
(used only in Choice and Set structures, trying to
- determine if tag satisfies the scheme)
+ determine if tag satisfies the schema)
:param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
before using it?
:returns: (Obj, remaining data)
# ASN.1 primitive types
########################################################################
-BooleanState = namedtuple("BooleanState", (
- "version",
- "value",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
-), **NAMEDTUPLE_KWARGS)
+BooleanState = namedtuple(
+ "BooleanState",
+ BasicState._fields + ("value",),
+ **NAMEDTUPLE_KWARGS
+)
class Boolean(Obj):
def __getstate__(self):
return BooleanState(
__version__,
- self._value,
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self._value,
)
def __setstate__(self, state):
super(Boolean, self).__setstate__(state)
self._value = state.value
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
def __nonzero__(self):
self._assert_ready()
yield pp
-IntegerState = namedtuple("IntegerState", (
- "version",
- "specs",
- "value",
- "bound_min",
- "bound_max",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
-), **NAMEDTUPLE_KWARGS)
+IntegerState = namedtuple(
+ "IntegerState",
+ BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
+ **NAMEDTUPLE_KWARGS
+)
class Integer(Obj):
def __getstate__(self):
return IntegerState(
__version__,
- self.specs,
- self._value,
- self._bound_min,
- self._bound_max,
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self.specs,
+ self._value,
+ self._bound_min,
+ self._bound_max,
)
def __setstate__(self, state):
self._value = state.value
self._bound_min = state.bound_min
self._bound_max = state.bound_max
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
def __int__(self):
self._assert_ready()
@property
def named(self):
+ """Return named representation (if exists) of the value
+ """
for name, value in iteritems(self.specs):
if value == self._value:
return name
yield pp
-BitStringState = namedtuple("BitStringState", (
- "version",
- "specs",
- "value",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
- "tag_constructed",
- "defined",
-), **NAMEDTUPLE_KWARGS)
+BitStringState = namedtuple(
+ "BitStringState",
+ BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
+ **NAMEDTUPLE_KWARGS
+)
class BitString(Obj):
def __getstate__(self):
return BitStringState(
__version__,
- self.specs,
- self._value,
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self.specs,
+ self._value,
self.tag_constructed,
self.defined,
)
super(BitString, self).__setstate__(state)
self.specs = state.specs
self._value = state.value
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
self.tag_constructed = state.tag_constructed
self.defined = state.defined
@property
def bit_len(self):
+ """Returns number of bits in the string
+ """
self._assert_ready()
return self._value[0]
@property
def named(self):
+ """Named representation (if exists) of the bits
+
+ :returns: [str(name), ...]
+ """
return [name for name, bit in iteritems(self.specs) if self[bit]]
def __call__(
yield pp
-OctetStringState = namedtuple("OctetStringState", (
- "version",
- "value",
- "bound_min",
- "bound_max",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
- "tag_constructed",
- "defined",
-), **NAMEDTUPLE_KWARGS)
+OctetStringState = namedtuple(
+ "OctetStringState",
+ BasicState._fields + (
+ "value",
+ "bound_min",
+ "bound_max",
+ "tag_constructed",
+ "defined",
+ ),
+ **NAMEDTUPLE_KWARGS
+)
class OctetString(Obj):
def __getstate__(self):
return OctetStringState(
__version__,
- self._value,
- self._bound_min,
- self._bound_max,
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self._value,
+ self._bound_min,
+ self._bound_max,
self.tag_constructed,
self.defined,
)
self._value = state.value
self._bound_min = state.bound_min
self._bound_max = state.bound_max
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
self.tag_constructed = state.tag_constructed
self.defined = state.defined
yield pp
-NullState = namedtuple("NullState", (
- "version",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
-), **NAMEDTUPLE_KWARGS)
+NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
class Null(Obj):
self.ber_encoded,
)
- def __setstate__(self, state):
- super(Null, self).__setstate__(state)
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
-
def __eq__(self, their):
if not issubclass(their.__class__, Null):
return False
yield pp
-ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
- "version",
- "value",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
- "defines",
-), **NAMEDTUPLE_KWARGS)
+ObjectIdentifierState = namedtuple(
+ "ObjectIdentifierState",
+ BasicState._fields + ("value", "defines"),
+ **NAMEDTUPLE_KWARGS
+)
class ObjectIdentifier(Obj):
def __getstate__(self):
return ObjectIdentifierState(
__version__,
- self._value,
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self._value,
self.defines,
)
def __setstate__(self, state):
super(ObjectIdentifier, self).__setstate__(state)
self._value = state.value
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
self.defines = state.defines
def __iter__(self):
asn1_type_name = "BMPString"
-ChoiceState = namedtuple("ChoiceState", (
- "version",
- "specs",
- "value",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
-), **NAMEDTUPLE_KWARGS)
+ChoiceState = namedtuple(
+ "ChoiceState",
+ BasicState._fields + ("specs", "value",),
+ **NAMEDTUPLE_KWARGS
+)
class Choice(Obj):
def __getstate__(self):
return ChoiceState(
__version__,
- self.specs,
- copy(self._value),
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self.specs,
+ copy(self._value),
)
def __setstate__(self, state):
super(Choice, self).__setstate__(state)
self.specs = state.specs
self._value = state.value
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
def __eq__(self, their):
if (their.__class__ == tuple) and len(their) == 2:
@property
def choice(self):
+ """Name of the choice
+ """
self._assert_ready()
return self._value[0]
@property
def value(self):
+ """Value of underlying choice
+ """
self._assert_ready()
return self._value[1]
))
-AnyState = namedtuple("AnyState", (
- "version",
- "value",
- "tag",
- "expl",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
- "defined",
-), **NAMEDTUPLE_KWARGS)
+AnyState = namedtuple(
+ "AnyState",
+ BasicState._fields + ("value", "defined"),
+ **NAMEDTUPLE_KWARGS
+)
class Any(Obj):
def __getstate__(self):
return AnyState(
__version__,
- self._value,
self.tag,
self._expl,
+ None,
self.optional,
self.offset,
self.llen,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self._value,
self.defined,
)
def __setstate__(self, state):
super(Any, self).__setstate__(state)
self._value = state.value
- self.tag = state.tag
- self._expl = state.expl
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
self.defined = state.defined
def __eq__(self, their):
return decode_path + rel_path
-SequenceState = namedtuple("SequenceState", (
- "version",
- "specs",
- "value",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
-), **NAMEDTUPLE_KWARGS)
+SequenceState = namedtuple(
+ "SequenceState",
+ BasicState._fields + ("specs", "value",),
+ **NAMEDTUPLE_KWARGS
+)
class Sequence(Obj):
def __getstate__(self):
return SequenceState(
__version__,
- self.specs,
- {k: copy(v) for k, v in iteritems(self._value)},
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self.specs,
+ {k: copy(v) for k, v in iteritems(self._value)},
)
def __setstate__(self, state):
super(Sequence, self).__setstate__(state)
self.specs = state.specs
self._value = state.value
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
def __eq__(self, their):
if not isinstance(their, self.__class__):
return obj, tail
-SequenceOfState = namedtuple("SequenceOfState", (
- "version",
- "spec",
- "value",
- "bound_min",
- "bound_max",
- "tag",
- "expl",
- "default",
- "optional",
- "offset",
- "llen",
- "vlen",
- "expl_lenindef",
- "lenindef",
- "ber_encoded",
-), **NAMEDTUPLE_KWARGS)
+SequenceOfState = namedtuple(
+ "SequenceOfState",
+ BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
+ **NAMEDTUPLE_KWARGS
+)
class SequenceOf(Obj):
def __getstate__(self):
return SequenceOfState(
__version__,
- self.spec,
- [copy(v) for v in self._value],
- self._bound_min,
- self._bound_max,
self.tag,
self._expl,
self.default,
self.expl_lenindef,
self.lenindef,
self.ber_encoded,
+ self.spec,
+ [copy(v) for v in self._value],
+ self._bound_min,
+ self._bound_max,
)
def __setstate__(self, state):
self._value = state.value
self._bound_min = state.bound_min
self._bound_max = state.bound_max
- self.tag = state.tag
- self._expl = state.expl
- self.default = state.default
- self.optional = state.optional
- self.offset = state.offset
- self.llen = state.llen
- self.vlen = state.vlen
- self.expl_lenindef = state.expl_lenindef
- self.lenindef = state.lenindef
- self.ber_encoded = state.ber_encoded
def __eq__(self, their):
if isinstance(their, self.__class__):
if args.defines_by_path is not None:
ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
obj, tail = schema().decode(der, ctx=ctx)
+ from os import environ
print(pprinter(
obj,
oid_maps=oid_maps,