Library reference¶
Contents
Python ASN.1 DER/BER codec with abstract structures
This library allows you to marshal various structures in ASN.1 DER format, unmarshal them in BER/CER/DER ones.
>>> i = Integer(123)
>>> raw = i.encode()
>>> Integer().decode(raw) == i
True
There are primitive types, holding single values
(pyderasn.BitString
,
pyderasn.Boolean
,
pyderasn.Enumerated
,
pyderasn.GeneralizedTime
,
pyderasn.Integer
,
pyderasn.Null
,
pyderasn.ObjectIdentifier
,
pyderasn.OctetString
,
pyderasn.UTCTime
,
various strings
(pyderasn.BMPString
,
pyderasn.GeneralString
,
pyderasn.GraphicString
,
pyderasn.IA5String
,
pyderasn.ISO646String
,
pyderasn.NumericString
,
pyderasn.PrintableString
,
pyderasn.T61String
,
pyderasn.TeletexString
,
pyderasn.UniversalString
,
pyderasn.UTF8String
,
pyderasn.VideotexString
,
pyderasn.VisibleString
)),
constructed types, holding multiple primitive types
(pyderasn.Sequence
,
pyderasn.SequenceOf
,
pyderasn.Set
,
pyderasn.SetOf
),
and special types like
pyderasn.Any
and
pyderasn.Choice
.
Common for most types¶
Tags¶
Most types in ASN.1 has specific tag for them. Obj.tag_default
is
the default tag used during coding process. You can override it with
either IMPLICIT
(using impl
keyword argument), or
EXPLICIT
one (using expl
keyword argument). Both arguments take
raw binary string, containing that tag. You can not set implicit and
explicit tags simultaneously.
There are pyderasn.tag_ctxp()
and pyderasn.tag_ctxc()
functions, allowing you to easily create CONTEXT
PRIMITIVE
/CONSTRUCTED
tags, by specifying only the required tag
number. Pay attention that explicit tags always have constructed tag
(tag_ctxc
), but implicit tags for primitive types are primitive
(tag_ctxp
).
>>> Integer(impl=tag_ctxp(1))
[1] INTEGER
>>> Integer(expl=tag_ctxc(2))
[2] EXPLICIT INTEGER
Implicit tag is not explicitly shown.
Two objects of the same type, but with different implicit/explicit tags are not equal.
You can get object’s effective tag (either default or implicited) through
tag
property. You can decode it using pyderasn.tag_decode()
function:
>>> tag_decode(tag_ctxc(123))
(128, 32, 123)
>>> klass, form, num = tag_decode(tag_ctxc(123))
>>> klass == TagClassContext
True
>>> form == TagFormConstructed
True
To determine if object has explicit tag, use expled
boolean property
and expl_tag
property, returning explicit tag’s value.
Default/optional¶
Many objects in sequences could be OPTIONAL
and could have
DEFAULT
value. You can specify that object’s property using
corresponding keyword arguments.
>>> Integer(optional=True, default=123)
INTEGER 123 OPTIONAL DEFAULT
Those specifications do not play any role in primitive value encoding,
but are taken into account when dealing with sequences holding them. For
example TBSCertificate
sequence holds defaulted, explicitly tagged
version
field:
class Version(Integer):
schema = (
("v1", 0),
("v2", 1),
("v3", 2),
)
class TBSCertificate(Sequence):
schema = (
("version", Version(expl=tag_ctxc(0), default="v1")),
[...]
When default argument is used and value is not specified, then it equals to default one.
Size constraints¶
Some objects give ability to set value size constraints. This is either possible integer value, or allowed length of various strings and sequences. Constraints are set in the following way:
class X(...):
bounds = (MIN, MAX)
And values satisfaction is checked as: MIN <= X <= MAX
.
For simplicity you can also set bounds the following way:
bounded_x = X(bounds=(MIN, MAX))
If bounds are not satisfied, then pyderasn.BoundsError
is
raised.
Common methods¶
All objects have ready
boolean property, that tells if object is
ready to be encoded. If that kind of action is performed on unready
object, then pyderasn.ObjNotReady
exception will be raised.
All objects have copy()
method, that returns their copy, that can be
safely mutated.
Decoding¶
Decoding is performed using decode()
method. offset
optional
argument could be used to set initial object’s offset in the binary
data, for convenience. It returns decoded object and remaining
unmarshalled data (tail). Internally all work is done on
memoryview(data)
, and you can leave returning tail as a memoryview,
by specifying leavemm=True
argument.
When object is decoded, decoded
property is true and you can safely
use following properties:
offset
– position including initial offset where object’s tag startstlen
– length of object’s tagllen
– length of object’s length valuevlen
– length of object’s valuetlvlen
– length of the whole object
Pay attention that those values do not include anything related to explicit tag. If you want to know information about it, then use:
expled
– to know if explicit tag is setexpl_offset
(it is lesser thanoffset
)expl_tlen
,expl_llen
expl_vlen
(that actually equals to ordinarytlvlen
)fulloffset
– it equals toexpl_offset
if explicit tag is set,offset
otherwisefulllen
– it equals toexpl_len
if explicit tag is set,tlvlen
otherwise
When error occurs, pyderasn.DecodeError
is raised.
Pretty printing¶
All objects have pps()
method, that is a generator of
pyderasn.PP
namedtuple, holding various raw information
about the object. If pps
is called on sequences, then all underlying
PP
will be yielded.
You can use pyderasn.pp_console_row()
function, converting
those PP
to human readable string. Actually exactly it is used for
all object repr
. But it is easy to write custom formatters.
>>> from pyderasn import pprint
>>> encoded = Integer(-12345).encode()
>>> obj, tail = Integer().decode(encoded)
>>> print(pprint(obj))
0 [1,1, 2] INTEGER -12345
DEFINED BY¶
ASN.1 structures often have ANY and OCTET STRING fields, that are DEFINED BY some previously met ObjectIdentifier. This library provides ability to specify mapping between some OID and field that must be decoded with specific specification.
defines kwarg¶
pyderasn.ObjectIdentifier
field inside
pyderasn.Sequence
can hold mapping between OIDs and
necessary for decoding structures. For example, CMS (RFC 5652)
container:
class ContentInfo(Sequence):
schema = (
("contentType", ContentType(defines=((("content",), {
id_digestedData: DigestedData(),
id_signedData: SignedData(),
}),))),
("content", Any(expl=tag_ctxc(0))),
)
contentType
field tells that it defines that content
must be
decoded with SignedData
specification, if contentType
equals to
id-signedData
. The same applies to DigestedData
. If
contentType
contains unknown OID, then no automatic decoding is
done.
You can specify multiple fields, that will be autodecoded – that is why
defines
kwarg is a sequence. You can specify defined field
relatively or absolutely to current decode path. For example defines
for AlgorithmIdentifier of X.509’s
tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm
:
(
(("parameters",), {
id_ecPublicKey: ECParameters(),
id_GostR3410_2001: GostR34102001PublicKeyParameters(),
}),
(("..", "subjectPublicKey"), {
id_rsaEncryption: RSAPublicKey(),
id_GostR3410_2001: OctetString(),
}),
),
tells that if certificate’s SPKI algorithm is GOST R 34.10-2001, then autodecode its parameters inside SPKI’s algorithm and its public key itself.
Following types can be automatically decoded (DEFINED BY):
pyderasn.Any
pyderasn.BitString
(that is multiple of 8 bits)pyderasn.OctetString
pyderasn.SequenceOf
/pyderasn.SetOf
Any
/BitString
/OctetString
-s
When any of those fields is automatically decoded, then .defined
attribute contains (OID, value)
tuple. OID
tells by which OID it
was defined, value
contains corresponding decoded value. For example
above, content_info["content"].defined == (id_signedData, signed_data)
.
defines_by_path context option¶
Sometimes you either can not or do not want to explicitly set defines
in the scheme. You can dynamically apply those definitions when calling
.decode()
method.
Specify defines_by_path
key in the decode context. Its
value must be sequence of following tuples:
(decode_path, defines)
where decode_path
is a tuple holding so-called decode path to the
exact pyderasn.ObjectIdentifier
field you want to apply
defines
, holding exactly the same value as accepted in its keyword
argument.
For example, again for CMS, you want to automatically decode
SignedData
and CMC’s (RFC 5272) PKIData
and PKIResponse
structures it may hold. Also, automatically decode controlSequence
of PKIResponse
:
content_info, tail = ContentInfo().decode(data, defines_by_path=(
(
("contentType",),
((("content",), {id_signedData: SignedData()}),),
),
(
(
"content",
DecodePathDefBy(id_signedData),
"encapContentInfo",
"eContentType",
),
((("eContent",), {
id_cct_PKIData: PKIData(),
id_cct_PKIResponse: PKIResponse(),
})),
),
(
(
"content",
DecodePathDefBy(id_signedData),
"encapContentInfo",
"eContent",
DecodePathDefBy(id_cct_PKIResponse),
"controlSequence",
any,
"attrType",
),
((("attrValues",), {
id_cmc_recipientNonce: RecipientNonce(),
id_cmc_senderNonce: SenderNonce(),
id_cmc_statusInfoV2: CMCStatusInfoV2(),
id_cmc_transactionId: TransactionId(),
})),
),
))
Pay attention for pyderasn.DecodePathDefBy
and any
.
First function is useful for path construction when some automatic
decoding is already done. any
means literally any value it meet –
useful for SEQUENCE/SET OF-s.
BER encoding¶
By default PyDERASN accepts only DER encoded data. It always encodes to
DER. But you can optionally enable BER decoding with setting bered
context argument to True. Indefinite lengths and
constructed primitive types should be parsed successfully.
- If object is encoded in BER form (not the DER one), then
bered
attribute is set to True. OnlyBOOLEAN
,BIT STRING
,OCTET STRING
can contain it. - If object has an indefinite length encoding, then its
lenindef
attribute is set to True. OnlyBIT STRING
,OCTET STRING
,SEQUENCE
,SET
,SEQUENCE OF
,SET OF
,ANY
can contain it. - If object has an indefinite length encoded explicit tag, then
expl_lenindef
is set to True.
EOC (end-of-contents) token’s length is taken in advance in object’s value length.
Allow explicit tag out-of-bound¶
Invalid BER encoding could contain EXPLICIT
tag containing more than
one value, more than one object. If you set allow_expl_oob
context
option to True, then no error will be raised and that invalid encoding
will be silently further processed. But pay attention that offsets and
lengths will be invalid in that case.
Warning
This option should be used only for skipping some decode errors, just to see the decoded structure somehow.
Primitive types¶
Boolean¶
-
class
pyderasn.
Boolean
(value=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ BOOLEAN
boolean type>>> b = Boolean(True) BOOLEAN True >>> b == Boolean(True) True >>> bool(b) True
-
__init__
(value=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either boolean type, or
pyderasn.Boolean
object - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either boolean type, or
-
Integer¶
-
class
pyderasn.
Integer
(value=None, bounds=None, impl=None, expl=None, default=None, optional=False, _specs=None, _decoded=(0, 0, 0))¶ INTEGER
integer type>>> b = Integer(-123) INTEGER -123 >>> b == Integer(-123) True >>> int(b) -123
>>> Integer(2, bounds=(1, 3)) INTEGER 2 >>> Integer(5, bounds=(1, 3)) Traceback (most recent call last): pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
class Version(Integer): schema = ( ("v1", 0), ("v2", 1), ("v3", 2), )
>>> v = Version("v1") Version INTEGER v1 >>> int(v) 0 >>> v.named 'v1' >>> v.specs {'v3': 2, 'v1': 0, 'v2': 1}
-
__init__
(value=None, bounds=None, impl=None, expl=None, default=None, optional=False, _specs=None, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either integer type, named value
(if
schema
is specified in the class), orpyderasn.Integer
object - bounds – set
(MIN, MAX)
value constraint. (-inf, +inf) by default - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either integer type, named value
(if
-
BitString¶
-
class
pyderasn.
BitString
(value=None, impl=None, expl=None, default=None, optional=False, _specs=None, _decoded=(0, 0, 0))¶ BIT STRING
bit string type>>> BitString(b"hello world") BIT STRING 88 bits 68656c6c6f20776f726c64 >>> bytes(b) b'hello world' >>> b == b"hello world" True >>> b.bit_len 88
>>> BitString("'0A3B5F291CD'H") BIT STRING 44 bits 0a3b5f291cd0 >>> b = BitString("'010110000000'B") BIT STRING 12 bits 5800 >>> b.bit_len 12 >>> b[0], b[1], b[2], b[3] (False, True, False, True) >>> b[1000] False >>> [v for v in b] [False, True, False, True, True, False, False, False, False, False, False, False]
class KeyUsage(BitString): schema = ( ("digitalSignature", 0), ("nonRepudiation", 1), ("keyEncipherment", 2), )
>>> b = KeyUsage(("keyEncipherment", "nonRepudiation")) KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment >>> b.named ['nonRepudiation', 'keyEncipherment'] >>> b.specs {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
Note
Pay attention that BIT STRING can be encoded both in primitive and constructed forms. Decoder always checks constructed form tag additionally to specified primitive one. If BER decoding is not enabled, then decoder will fail, because of DER restrictions.
-
__init__
(value=None, impl=None, expl=None, default=None, optional=False, _specs=None, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either binary type, tuple of named
values (if
schema
is specified in the class), string in'XXX...'B
form, orpyderasn.BitString
object - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either binary type, tuple of named
values (if
-
OctetString¶
-
class
pyderasn.
OctetString
(value=None, bounds=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ OCTET STRING
binary string type>>> s = OctetString(b"hello world") OCTET STRING 11 bytes 68656c6c6f20776f726c64 >>> s == OctetString(b"hello world") True >>> bytes(s) b'hello world'
>>> OctetString(b"hello", bounds=(4, 4)) Traceback (most recent call last): pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4 >>> OctetString(b"hell", bounds=(4, 4)) OCTET STRING 4 bytes 68656c6c
Note
Pay attention that OCTET STRING can be encoded both in primitive and constructed forms. Decoder always checks constructed form tag additionally to specified primitive one. If BER decoding is not enabled, then decoder will fail, because of DER restrictions.
-
__init__
(value=None, bounds=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either binary type, or
pyderasn.OctetString
object - bounds – set
(MIN, MAX)
value size constraint. (-inf, +inf) by default - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either binary type, or
-
Null¶
-
class
pyderasn.
Null
(value=None, impl=None, expl=None, optional=False, _decoded=(0, 0, 0))¶ NULL
null object>>> n = Null() NULL >>> n.ready True
-
__init__
(value=None, impl=None, expl=None, optional=False, _decoded=(0, 0, 0))¶ Parameters: - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - optional (bool) – is object
OPTIONAL
in sequence
- impl (bytes) – override default tag with
-
ObjectIdentifier¶
-
class
pyderasn.
ObjectIdentifier
(value=None, defines=(), impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ OBJECT IDENTIFIER
OID type>>> oid = ObjectIdentifier((1, 2, 3)) OBJECT IDENTIFIER 1.2.3 >>> oid == ObjectIdentifier("1.2.3") True >>> tuple(oid) (1, 2, 3) >>> str(oid) '1.2.3' >>> oid + (4, 5) + ObjectIdentifier("1.7") OBJECT IDENTIFIER 1.2.3.4.5.1.7
>>> str(ObjectIdentifier((3, 1))) Traceback (most recent call last): pyderasn.InvalidOID: unacceptable first arc value
-
__init__
(value=None, defines=(), impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either tuples of integers,
string of “.”-concatenated integers, or
pyderasn.ObjectIdentifier
object - defines – sequence of tuples. Each tuple has two elements.
First one is relative to current one decode
path, aiming to the field defined by that OID.
Read about relative path in
pyderasn.abs_decode_path()
. Second tuple element is{OID: pyderasn.Obj()}
dictionary, mapping between current OID value and structure applied to defined field. Read about DEFINED BY - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either tuples of integers,
string of “.”-concatenated integers, or
-
Enumerated¶
-
class
pyderasn.
Enumerated
(value=None, impl=None, expl=None, default=None, optional=False, _specs=None, _decoded=(0, 0, 0), bounds=None)¶ ENUMERATED
integer typeThis type is identical to
pyderasn.Integer
, but requires schema to be specified and does not accept values missing from it.
CommonString¶
-
class
pyderasn.
CommonString
(value=None, bounds=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Common class for all strings
Everything resembles
pyderasn.OctetString
, except ability to deal with unicode text strings.>>> hexenc("привет мир".encode("utf-8")) 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180' >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80")) True >>> s = UTF8String("привет мир") UTF8String UTF8String привет мир >>> str(s) 'привет мир' >>> hexenc(bytes(s)) 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
>>> PrintableString("привет мир") Traceback (most recent call last): pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
>>> BMPString("ада", bounds=(2, 2)) Traceback (most recent call last): pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2 >>> s = BMPString("ад", bounds=(2, 2)) >>> s.encoding 'utf-16-be' >>> hexenc(bytes(s)) '04300434'
Class Text Encoding pyderasn.UTF8String
utf-8 pyderasn.NumericString
ascii pyderasn.PrintableString
ascii pyderasn.TeletexString
ascii pyderasn.T61String
ascii pyderasn.VideotexString
iso-8859-1 pyderasn.IA5String
ascii pyderasn.GraphicString
iso-8859-1 pyderasn.VisibleString
ascii pyderasn.ISO646String
ascii pyderasn.GeneralString
iso-8859-1 pyderasn.UniversalString
utf-32-be pyderasn.BMPString
utf-16-be
NumericString¶
-
class
pyderasn.
NumericString
(value=None, bounds=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Numeric string
Its value is properly sanitized: only ASCII digits can be stored.
UTCTime¶
-
class
pyderasn.
UTCTime
(value=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0), bounds=None)¶ UTCTime
datetime type>>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123)) UTCTime UTCTime 2017-09-30T22:07:50 >>> str(t) '170930220750Z' >>> bytes(t) b'170930220750Z' >>> t.todatetime() datetime.datetime(2017, 9, 30, 22, 7, 50) >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime() datetime.datetime(1957, 9, 30, 22, 7, 50)
-
__init__
(value=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0), bounds=None)¶ Parameters: - value – set the value. Either datetime type, or
pyderasn.UTCTime
object - impl (bytes) – override default tag with
IMPLICIT
one - expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either datetime type, or
-
todatetime
()¶ Convert to datetime
Returns: datetime Pay attention that UTCTime can not hold full year, so all years having < 50 years are treated as 20xx, 19xx otherwise, according to X.509 recomendation.
-
GeneralizedTime¶
-
class
pyderasn.
GeneralizedTime
(value=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0), bounds=None)¶ GeneralizedTime
datetime typeThis type is similar to
pyderasn.UTCTime
.>>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123)) GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123 >>> str(t) '20170930220750.000123Z' >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50)) GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
Special types¶
Choice¶
-
class
pyderasn.
Choice
(value=None, schema=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ CHOICE
special typeclass GeneralName(Choice): schema = ( ("rfc822Name", IA5String(impl=tag_ctxp(1))), ("dNSName", IA5String(impl=tag_ctxp(2))), )
>>> gn = GeneralName() GeneralName CHOICE >>> gn["rfc822Name"] = IA5String("foo@bar.baz") GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz] >>> gn["dNSName"] = IA5String("bar.baz") GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz] >>> gn["rfc822Name"] None >>> gn["dNSName"] [2] IA5String IA5 bar.baz >>> gn.choice 'dNSName' >>> gn.value == gn["dNSName"] True >>> gn.specs OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
>>> GeneralName(("rfc822Name", IA5String("foo@bar.baz"))) GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
-
__init__
(value=None, schema=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either
(choice, value)
tuple, orpyderasn.Choice
object - impl (bytes) – can not be set, do not use it
- expl (bytes) – override default tag with
EXPLICIT
one - default – set default value. Type same as in
value
- optional (bool) – is object
OPTIONAL
in sequence
- value – set the value. Either
-
PrimitiveTypes¶
-
class
pyderasn.
PrimitiveTypes
(value=None, schema=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Predefined
CHOICE
for all generic primitive typesIt could be useful for general decoding of some unspecified values:
>>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value OCTET STRING 3 bytes 666f6f >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value INTEGER 1193046
Any¶
-
class
pyderasn.
Any
(value=None, expl=None, optional=False, _decoded=(0, 0, 0))¶ ANY
special type>>> Any(Integer(-123)) ANY 020185 >>> a = Any(OctetString(b"hello world").encode()) ANY 040b68656c6c6f20776f726c64 >>> hexenc(bytes(a)) b'0x040x0bhello world'
-
__init__
(value=None, expl=None, optional=False, _decoded=(0, 0, 0))¶ Parameters: - value – set the value. Either any kind of pyderasn’s ready object, or bytes. Pay attention that no validation is performed is raw binary value is valid TLV
- expl (bytes) – override default tag with
EXPLICIT
one - optional (bool) – is object
OPTIONAL
in sequence
-
Constructed types¶
Sequence¶
-
class
pyderasn.
Sequence
(value=None, schema=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ SEQUENCE
structure typeYou have to make specification of sequence:
class Extension(Sequence): schema = ( ("extnID", ObjectIdentifier()), ("critical", Boolean(default=False)), ("extnValue", OctetString()), )
Then, you can work with it as with dictionary.
>>> ext = Extension() >>> Extension().specs OrderedDict([ ('extnID', OBJECT IDENTIFIER), ('critical', BOOLEAN False OPTIONAL DEFAULT), ('extnValue', OCTET STRING), ]) >>> ext["extnID"] = "1.2.3" Traceback (most recent call last): pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'> >>> ext["extnID"] = ObjectIdentifier("1.2.3")
You can determine if sequence is ready to be encoded:
>>> ext.ready False >>> ext.encode() Traceback (most recent call last): pyderasn.ObjNotReady: object is not ready: extnValue >>> ext["extnValue"] = OctetString(b"foobar") >>> ext.ready True
Value you want to assign, must have the same type as in corresponding specification, but it can have different tags, optional/default attributes – they will be taken from specification automatically:
class TBSCertificate(Sequence): schema = ( ("version", Version(expl=tag_ctxc(0), default="v1")), [...]
>>> tbs = TBSCertificate() >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
Assign
None
to remove value from sequence.You can set values in Sequence during its initialization:
>>> AlgorithmIdentifier(( ("algorithm", ObjectIdentifier("1.2.3")), ("parameters", Any(Null())) )) AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
You can determine if value exists/set in the sequence and take its value:
>>> "extnID" in ext, "extnValue" in ext, "critical" in ext (True, True, False) >>> ext["extnID"] OBJECT IDENTIFIER 1.2.3
But pay attention that if value has default, then it won’t be (not in) in the sequence (because
DEFAULT
must not be encoded in DER), but you can read its value:>>> "critical" in ext, ext["critical"] (False, BOOLEAN False) >>> ext["critical"] = Boolean(True) >>> "critical" in ext, ext["critical"] (True, BOOLEAN True)
All defaulted values are always optional.
Warning
When decoded DER contains defaulted value inside, then technically this is not valid DER encoding. But we allow and pass it by default. Of course reencoding of that kind of DER will result in different binary representation (validly without defaulted value inside). You can enable strict defaulted values existence validation by setting
"strict_default_existence": True
context option – decoding process will raise an exception if defaulted value is met.Two sequences are equal if they have equal specification (schema), implicit/explicit tagging and the same values.
Set¶
-
class
pyderasn.
Set
(value=None, schema=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ SET
structure typeIts usage is identical to
pyderasn.Sequence
.
SequenceOf¶
-
class
pyderasn.
SequenceOf
(value=None, schema=None, bounds=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ SEQUENCE OF
sequence typeFor that kind of type you must specify the object it will carry on (bounds are for example here, not required):
class Ints(SequenceOf): schema = Integer() bounds = (0, 2)
>>> ints = Ints() >>> ints.append(Integer(123)) >>> ints.append(Integer(234)) >>> ints Ints SEQUENCE OF[INTEGER 123, INTEGER 234] >>> [int(i) for i in ints] [123, 234] >>> ints.append(Integer(345)) Traceback (most recent call last): pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2 >>> ints[1] INTEGER 234 >>> ints[1] = Integer(345) >>> ints Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
Also you can initialize sequence with preinitialized values:
>>> ints = Ints([Integer(123), Integer(234)])
SetOf¶
-
class
pyderasn.
SetOf
(value=None, schema=None, bounds=None, impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ SET OF
sequence typeIts usage is identical to
pyderasn.SequenceOf
.
Various¶
-
pyderasn.
abs_decode_path
(decode_path, rel_path)¶ Create an absolute decode path from current and relative ones
Parameters: - decode_path – current decode path, starting point. Tuple of strings
- rel_path – relative path to
decode_path
. Tuple of strings. If first tuple’s element is “/”, then treat it as an absolute path, ignoringdecode_path
as starting point. Also this tuple can contain “..” elements, stripping the leading element fromdecode_path
>>> abs_decode_path(("foo", "bar"), ("baz", "whatever")) ("foo", "bar", "baz", "whatever") >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever")) ("foo", "whatever") >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever")) ("baz", "whatever")
-
pyderasn.
hexenc
(data)¶ Hexadecimal string to binary data convert
-
pyderasn.
hexdec
(data)¶ Binary data to hexadecimal string convert
-
pyderasn.
tag_encode
(num, klass=0, form=0)¶ Encode tag to binary form
Parameters: - num (int) – tag’s number
- klass (int) – tag’s class (
pyderasn.TagClassUniversal
,pyderasn.TagClassContext
,pyderasn.TagClassApplication
,pyderasn.TagClassPrivate
) - form (int) – tag’s form (
pyderasn.TagFormPrimitive
,pyderasn.TagFormConstructed
)
-
pyderasn.
tag_decode
(tag)¶ Decode tag from binary form
Warning
No validation is performed, assuming that it has already passed.
It returns tuple with three integers, as
pyderasn.tag_encode()
accepts.
-
pyderasn.
tag_ctxp
(num)¶ Create CONTEXT PRIMITIVE tag
-
pyderasn.
tag_ctxc
(num)¶ Create CONTEXT CONSTRUCTED tag
-
class
pyderasn.
Obj
(impl=None, expl=None, default=None, optional=False, _decoded=(0, 0, 0))¶ Common ASN.1 object class
All ASN.1 types are inherited from it. It has metaclass that automatically adds
__slots__
to all inherited classes.
-
class
pyderasn.
DecodeError
(msg='', klass=None, decode_path=(), offset=0)¶ -
__init__
(msg='', klass=None, decode_path=(), offset=0)¶ Parameters: - msg (str) – reason of decode failing
- klass – optional exact DecodeError inherited class (like
NotEnoughData
,TagMismatch
,InvalidLength
) - decode_path – tuple of strings. It contains human readable names of the fields through which decoding process has passed
- offset (int) – binary offset where failure happened
-
-
class
pyderasn.
NotEnoughData
(msg='', klass=None, decode_path=(), offset=0)¶
-
class
pyderasn.
LenIndefForm
(msg='', klass=None, decode_path=(), offset=0)¶
-
class
pyderasn.
TagMismatch
(msg='', klass=None, decode_path=(), offset=0)¶
-
class
pyderasn.
InvalidLength
(msg='', klass=None, decode_path=(), offset=0)¶
-
class
pyderasn.
InvalidOID
(msg='', klass=None, decode_path=(), offset=0)¶
-
class
pyderasn.
ObjUnknown
(name)¶
-
class
pyderasn.
ObjNotReady
(name)¶
-
class
pyderasn.
InvalidValueType
(expected_types)¶
-
class
pyderasn.
BoundsError
(bound_min, value, bound_max)¶