cryptoparser 1.4.0__tar.gz → 1.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CHANGELOG.rst +30 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/PKG-INFO +5 -5
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/requires.txt +1 -1
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/top_level.txt +2 -1
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/PKG-INFO +5 -5
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/README.rst +3 -3
- cryptoparser-1.5.0/cryptoparser/ike/common.py +544 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/ikev1.py +348 -15
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/ikev2.py +656 -20
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/isakmp.py +123 -48
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser.spec +19 -3
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/changelog +19 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/rules +1 -1
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/features.rst +7 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/pyproject.toml +2 -2
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev1_payload.py +329 -37
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev2_notify.py +8 -2
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev2_payload.py +520 -34
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_isakmp.py +104 -9
- cryptoparser-1.4.0/cryptoparser/ike/common.py +0 -236
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.coveragerc +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.gitignore +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.gitlab-ci.yml +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.gitmodules +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.pylintrc +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.readthedocs.yaml +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CONTRIBUTING.rst +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/SOURCES.txt +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/dependency_links.txt +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/LICENSE.txt +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/MANIFEST.in +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/__setup__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/base.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/classes.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/exception.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/field.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/parse.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/utils.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/x509.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/dnsrec/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/dnsrec/record.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/dnsrec/txt.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/header.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/parse.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/key.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/record.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/subprotocol.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/algorithm.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/ciphersuite.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/extension.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/grease.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/ldap.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/mysql.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/openvpn.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/postgresql.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/rdp.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/record.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/subprotocol.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/control +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/copyright +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/source/format +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/watch +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/.gitignore +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/changelog.rst +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/conf.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/development.rst +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/index.rst +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/setup.cfg +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/setup.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/ecc256.badssl.com.pem +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/rsa8192.badssl.com.pem +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/rsa8192.badssl.com_certificate.crt +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/rsa8192.badssl.com_root_ca.crt +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/snakeoil_cert.pem +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/classes.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_algorithm.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_base.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_classes.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_exception.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_field.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_parse.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_utils.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_x509.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/dnsrec/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/dnsrec/test_record.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/dnsrec/test_txt.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/classes.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/test_header.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/test_version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/classes.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev1_sa.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev2_sa.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_ciphersuites.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_key.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_record.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_subprotocol.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_version.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/__init__.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/classes.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_alert.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_application_data.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_change_cipher_spec.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_ciphersuite.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_extension.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_grease.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_handshake.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_ldap.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_mysql.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_openvpn.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_postgresql.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_rdp.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_record.py +0 -0
- {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_version.py +0 -0
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
------------------
|
|
6
|
+
1.5.0 - 2026-07-31
|
|
7
|
+
------------------
|
|
8
|
+
|
|
9
|
+
Features
|
|
10
|
+
========
|
|
11
|
+
|
|
12
|
+
- IKE (``ike``)
|
|
13
|
+
|
|
14
|
+
- add IKEv1 and IKEv2 certificate payload parsing (#103)
|
|
15
|
+
- add IKEv1 identification payload parsing (#103)
|
|
16
|
+
- add IKEv1 signature payload parsing (#103)
|
|
17
|
+
- add IKEv2 identification payload parsing (#103)
|
|
18
|
+
- add IKEv2 authentication payload parsing (#103)
|
|
19
|
+
- add IKEv2 extensible authentication protocol payload parsing (#103)
|
|
20
|
+
- add IKEv2 encrypted and authenticated payload parsing (#103)
|
|
21
|
+
- keep IKEv1 and IKEv2 payloads of unknown type unparsed instead of rejecting the message (#103)
|
|
22
|
+
- add getter for the distinguished name of the IKEv1 certificate request payload (#103)
|
|
23
|
+
- add getter for the certification authority hashes of the IKEv2 certificate request payload (#103)
|
|
24
|
+
|
|
25
|
+
Refactor
|
|
26
|
+
========
|
|
27
|
+
|
|
28
|
+
- IKE (``ike``)
|
|
29
|
+
|
|
30
|
+
- parse the IKEv1 and IKEv2 identification payload data according to the identification type (#103)
|
|
31
|
+
- parse the digital signature envelope of the IKEv2 authentication payload (#103)
|
|
32
|
+
- split the ISAKMP message parsing and composing into header and payload chain steps (#103)
|
|
33
|
+
- use typed values in the IKEv2 signature hash algorithms notify payload (#103)
|
|
34
|
+
|
|
5
35
|
------------------
|
|
6
36
|
1.4.0 - 2026-07-17
|
|
7
37
|
------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: An analysis oriented security protocol parser and generator
|
|
5
5
|
Author-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
6
6
|
Maintainer-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
@@ -39,7 +39,7 @@ Description-Content-Type: text/x-rst
|
|
|
39
39
|
License-File: LICENSE.txt
|
|
40
40
|
Requires-Dist: asn1crypto
|
|
41
41
|
Requires-Dist: attrs
|
|
42
|
-
Requires-Dist: cryptodatahub==1.
|
|
42
|
+
Requires-Dist: cryptodatahub==1.5.0
|
|
43
43
|
Requires-Dist: urllib3
|
|
44
44
|
Provides-Extra: tests
|
|
45
45
|
Requires-Dist: pyfakefs; extra == "tests"
|
|
@@ -60,9 +60,9 @@ Dynamic: license-file
|
|
|
60
60
|
:alt: Documentation
|
|
61
61
|
:target: https://cryptoparser.readthedocs.io
|
|
62
62
|
|
|
63
|
-
**CryptoParser** is a cryptographic protocol (TLS, SSH) and security-related protocol piece (HTTP headers) parser.
|
|
64
|
-
is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support
|
|
65
|
-
|
|
63
|
+
**CryptoParser** is a cryptographic protocol (IKE, TLS, SSH) and security-related protocol piece (HTTP headers) parser.
|
|
64
|
+
It is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support testing
|
|
65
|
+
cryptographic libraries or analysing cryptography-realted settings of application servers such as
|
|
66
66
|
`CryptoLyzer <https://cryptolyzer.readthedocs.io/>`__ does.
|
|
67
67
|
|
|
68
68
|
-----
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: An analysis oriented security protocol parser and generator
|
|
5
5
|
Author-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
6
6
|
Maintainer-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
@@ -39,7 +39,7 @@ Description-Content-Type: text/x-rst
|
|
|
39
39
|
License-File: LICENSE.txt
|
|
40
40
|
Requires-Dist: asn1crypto
|
|
41
41
|
Requires-Dist: attrs
|
|
42
|
-
Requires-Dist: cryptodatahub==1.
|
|
42
|
+
Requires-Dist: cryptodatahub==1.5.0
|
|
43
43
|
Requires-Dist: urllib3
|
|
44
44
|
Provides-Extra: tests
|
|
45
45
|
Requires-Dist: pyfakefs; extra == "tests"
|
|
@@ -60,9 +60,9 @@ Dynamic: license-file
|
|
|
60
60
|
:alt: Documentation
|
|
61
61
|
:target: https://cryptoparser.readthedocs.io
|
|
62
62
|
|
|
63
|
-
**CryptoParser** is a cryptographic protocol (TLS, SSH) and security-related protocol piece (HTTP headers) parser.
|
|
64
|
-
is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support
|
|
65
|
-
|
|
63
|
+
**CryptoParser** is a cryptographic protocol (IKE, TLS, SSH) and security-related protocol piece (HTTP headers) parser.
|
|
64
|
+
It is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support testing
|
|
65
|
+
cryptographic libraries or analysing cryptography-realted settings of application servers such as
|
|
66
66
|
`CryptoLyzer <https://cryptolyzer.readthedocs.io/>`__ does.
|
|
67
67
|
|
|
68
68
|
-----
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
:alt: Documentation
|
|
9
9
|
:target: https://cryptoparser.readthedocs.io
|
|
10
10
|
|
|
11
|
-
**CryptoParser** is a cryptographic protocol (TLS, SSH) and security-related protocol piece (HTTP headers) parser.
|
|
12
|
-
is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support
|
|
13
|
-
|
|
11
|
+
**CryptoParser** is a cryptographic protocol (IKE, TLS, SSH) and security-related protocol piece (HTTP headers) parser.
|
|
12
|
+
It is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support testing
|
|
13
|
+
cryptographic libraries or analysing cryptography-realted settings of application servers such as
|
|
14
14
|
`CryptoLyzer <https://cryptolyzer.readthedocs.io/>`__ does.
|
|
15
15
|
|
|
16
16
|
-----
|
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
import abc
|
|
3
|
+
import enum
|
|
4
|
+
import ipaddress
|
|
5
|
+
import typing
|
|
6
|
+
|
|
7
|
+
import attr
|
|
8
|
+
|
|
9
|
+
from cryptodatahub.common.exception import InvalidValue
|
|
10
|
+
from cryptodatahub.ike.algorithm import (
|
|
11
|
+
Ikev1IdType,
|
|
12
|
+
Ikev1PayloadType,
|
|
13
|
+
Ikev2IdType,
|
|
14
|
+
Ikev2PayloadType,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from cryptoparser.common.exception import InvalidType
|
|
18
|
+
from cryptoparser.common.parse import ParsableBase, ParserBinary, ComposerBinary
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@attr.s
|
|
22
|
+
class IkePayloadTypeUnknown(ParsableBase):
|
|
23
|
+
"""Wrapper for an unknown IKE payload-type code (RFC 2408 §3.10, RFC 7296 §3.2)."""
|
|
24
|
+
|
|
25
|
+
code: int = attr.ib(validator=attr.validators.instance_of(int))
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def get_byte_num(cls):
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def _parse(cls, parsable):
|
|
33
|
+
parser = ParserBinary(parsable)
|
|
34
|
+
parser.parse_numeric('code', cls.get_byte_num())
|
|
35
|
+
return cls(parser['code']), parser.parsed_length
|
|
36
|
+
|
|
37
|
+
def compose(self):
|
|
38
|
+
composer = ComposerBinary()
|
|
39
|
+
composer.compose_numeric(self.code, self.get_byte_num())
|
|
40
|
+
return composer.composed_bytes
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _IkePayloadTypeFactoryBase(ParsableBase):
|
|
44
|
+
"""Yield payload-type enum member or :class:`IkePayloadTypeUnknown` for unregistered wire codes."""
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
@abc.abstractmethod
|
|
48
|
+
def _get_enum_class(cls):
|
|
49
|
+
raise NotImplementedError()
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def _parse(cls, parsable):
|
|
53
|
+
parser = ParserBinary(parsable)
|
|
54
|
+
parser.parse_numeric('code', 1)
|
|
55
|
+
for enum_item in cls._get_enum_class():
|
|
56
|
+
if enum_item.value.code == parser['code']:
|
|
57
|
+
return enum_item, 1
|
|
58
|
+
return IkePayloadTypeUnknown(parser['code']), 1
|
|
59
|
+
|
|
60
|
+
def compose(self):
|
|
61
|
+
raise NotImplementedError()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Ikev1PayloadTypeFactory(_IkePayloadTypeFactoryBase):
|
|
65
|
+
@classmethod
|
|
66
|
+
def _get_enum_class(cls):
|
|
67
|
+
return Ikev1PayloadType
|
|
68
|
+
|
|
69
|
+
def compose(self):
|
|
70
|
+
raise NotImplementedError()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Ikev2PayloadTypeFactory(_IkePayloadTypeFactoryBase):
|
|
74
|
+
@classmethod
|
|
75
|
+
def _get_enum_class(cls):
|
|
76
|
+
return Ikev2PayloadType
|
|
77
|
+
|
|
78
|
+
def compose(self):
|
|
79
|
+
raise NotImplementedError()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@attr.s
|
|
83
|
+
class IkeIdentificationFqdnMixin:
|
|
84
|
+
"""Fully-qualified domain name (RFC 2407 §4.6.2.1, RFC 7296 §3.5)."""
|
|
85
|
+
|
|
86
|
+
identifier: str = attr.ib(validator=attr.validators.instance_of(str))
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def get_id_type_ikev1(cls):
|
|
90
|
+
return Ikev1IdType.FQDN
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def get_id_type_ikev2(cls):
|
|
94
|
+
return Ikev2IdType.FQDN
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def _decode_identifier(cls, id_data):
|
|
98
|
+
return id_data.decode('ascii', errors='replace')
|
|
99
|
+
|
|
100
|
+
def _encode_identifier(self):
|
|
101
|
+
return self.identifier.encode('ascii')
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@attr.s
|
|
105
|
+
class IkeIdentificationUserFqdnMixin:
|
|
106
|
+
"""User fully-qualified domain name (RFC 2407 §4.6.2.1)."""
|
|
107
|
+
|
|
108
|
+
identifier: str = attr.ib(validator=attr.validators.instance_of(str))
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def get_id_type_ikev1(cls):
|
|
112
|
+
return Ikev1IdType.USER_FQDN
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def get_id_type_ikev2(cls):
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def _decode_identifier(cls, id_data):
|
|
120
|
+
return id_data.decode('ascii', errors='replace')
|
|
121
|
+
|
|
122
|
+
def _encode_identifier(self):
|
|
123
|
+
return self.identifier.encode('ascii')
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@attr.s
|
|
127
|
+
class IkeIdentificationRfc822AddrMixin:
|
|
128
|
+
"""RFC 822 email address (RFC 7296 §3.5)."""
|
|
129
|
+
|
|
130
|
+
identifier: str = attr.ib(validator=attr.validators.instance_of(str))
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def get_id_type_ikev1(cls):
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
@classmethod
|
|
137
|
+
def get_id_type_ikev2(cls):
|
|
138
|
+
return Ikev2IdType.RFC822_ADDR
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def _decode_identifier(cls, id_data):
|
|
142
|
+
return id_data.decode('ascii', errors='replace')
|
|
143
|
+
|
|
144
|
+
def _encode_identifier(self):
|
|
145
|
+
return self.identifier.encode('ascii')
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@attr.s
|
|
149
|
+
class IkeIdentificationIpv4AddrMixin:
|
|
150
|
+
"""IPv4 address (RFC 2407 §4.6.2.1, RFC 7296 §3.5)."""
|
|
151
|
+
|
|
152
|
+
identifier: ipaddress.IPv4Address = attr.ib(
|
|
153
|
+
converter=ipaddress.IPv4Address,
|
|
154
|
+
validator=attr.validators.instance_of(ipaddress.IPv4Address),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def get_id_type_ikev1(cls):
|
|
159
|
+
return Ikev1IdType.IPV4_ADDR
|
|
160
|
+
|
|
161
|
+
@classmethod
|
|
162
|
+
def get_id_type_ikev2(cls):
|
|
163
|
+
return Ikev2IdType.IPV4_ADDR
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def _decode_identifier(cls, id_data):
|
|
167
|
+
if len(id_data) != 4:
|
|
168
|
+
raise InvalidType()
|
|
169
|
+
return ipaddress.IPv4Address(id_data)
|
|
170
|
+
|
|
171
|
+
def _encode_identifier(self):
|
|
172
|
+
return self.identifier.packed
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@attr.s
|
|
176
|
+
class IkeIdentificationIpv6AddrMixin:
|
|
177
|
+
"""IPv6 address (RFC 2407 §4.6.2.1, RFC 7296 §3.5)."""
|
|
178
|
+
|
|
179
|
+
identifier: ipaddress.IPv6Address = attr.ib(
|
|
180
|
+
converter=ipaddress.IPv6Address,
|
|
181
|
+
validator=attr.validators.instance_of(ipaddress.IPv6Address),
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def get_id_type_ikev1(cls):
|
|
186
|
+
return Ikev1IdType.IPV6_ADDR
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def get_id_type_ikev2(cls):
|
|
190
|
+
return Ikev2IdType.IPV6_ADDR
|
|
191
|
+
|
|
192
|
+
@classmethod
|
|
193
|
+
def _decode_identifier(cls, id_data):
|
|
194
|
+
if len(id_data) != 16:
|
|
195
|
+
raise InvalidType()
|
|
196
|
+
return ipaddress.IPv6Address(id_data)
|
|
197
|
+
|
|
198
|
+
def _encode_identifier(self):
|
|
199
|
+
return self.identifier.packed
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@attr.s
|
|
203
|
+
class IkeIdentificationDerAsn1DnMixin:
|
|
204
|
+
"""DER-encoded ASN.1 X.500 Distinguished Name (RFC 2407 §4.6.2.1, RFC 7296 §3.5)."""
|
|
205
|
+
|
|
206
|
+
identifier: typing.Union[bytes, bytearray] = attr.ib(
|
|
207
|
+
validator=attr.validators.instance_of((bytes, bytearray)),
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def get_id_type_ikev1(cls):
|
|
212
|
+
return Ikev1IdType.DER_ASN1_DN
|
|
213
|
+
|
|
214
|
+
@classmethod
|
|
215
|
+
def get_id_type_ikev2(cls):
|
|
216
|
+
return Ikev2IdType.DER_ASN1_DN
|
|
217
|
+
|
|
218
|
+
@classmethod
|
|
219
|
+
def _decode_identifier(cls, id_data):
|
|
220
|
+
return id_data
|
|
221
|
+
|
|
222
|
+
def _encode_identifier(self):
|
|
223
|
+
return bytes(self.identifier)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@attr.s
|
|
227
|
+
class IkeIdentificationKeyIdMixin:
|
|
228
|
+
"""Opaque vendor-specific key identifier (RFC 2407 §4.6.2.1, RFC 7296 §3.5)."""
|
|
229
|
+
|
|
230
|
+
identifier: typing.Union[bytes, bytearray] = attr.ib(
|
|
231
|
+
validator=attr.validators.instance_of((bytes, bytearray)),
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
@classmethod
|
|
235
|
+
def get_id_type_ikev1(cls):
|
|
236
|
+
return Ikev1IdType.KEY_ID
|
|
237
|
+
|
|
238
|
+
@classmethod
|
|
239
|
+
def get_id_type_ikev2(cls):
|
|
240
|
+
return Ikev2IdType.KEY_ID
|
|
241
|
+
|
|
242
|
+
@classmethod
|
|
243
|
+
def _decode_identifier(cls, id_data):
|
|
244
|
+
return id_data
|
|
245
|
+
|
|
246
|
+
def _encode_identifier(self):
|
|
247
|
+
return bytes(self.identifier)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@attr.s
|
|
251
|
+
class IkeIdentificationDerAsn1GnMixin:
|
|
252
|
+
"""DER-encoded ASN.1 X.500 General Name (RFC 2407 §4.6.2.1, RFC 7296 §3.5)."""
|
|
253
|
+
|
|
254
|
+
identifier: typing.Union[bytes, bytearray] = attr.ib(
|
|
255
|
+
validator=attr.validators.instance_of((bytes, bytearray)),
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
@classmethod
|
|
259
|
+
def get_id_type_ikev1(cls):
|
|
260
|
+
return Ikev1IdType.DER_ASN1_GN
|
|
261
|
+
|
|
262
|
+
@classmethod
|
|
263
|
+
def get_id_type_ikev2(cls):
|
|
264
|
+
return Ikev2IdType.DER_ASN1_GN
|
|
265
|
+
|
|
266
|
+
@classmethod
|
|
267
|
+
def _decode_identifier(cls, id_data):
|
|
268
|
+
return id_data
|
|
269
|
+
|
|
270
|
+
def _encode_identifier(self):
|
|
271
|
+
return bytes(self.identifier)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@attr.s
|
|
275
|
+
class IkeIdentificationFcNameMixin:
|
|
276
|
+
"""Fibre Channel name (RFC 4595, RFC 7296 §3.5)."""
|
|
277
|
+
|
|
278
|
+
identifier: typing.Union[bytes, bytearray] = attr.ib(
|
|
279
|
+
validator=attr.validators.instance_of((bytes, bytearray)),
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
@classmethod
|
|
283
|
+
def get_id_type_ikev1(cls):
|
|
284
|
+
return None
|
|
285
|
+
|
|
286
|
+
@classmethod
|
|
287
|
+
def get_id_type_ikev2(cls):
|
|
288
|
+
return Ikev2IdType.FC_NAME
|
|
289
|
+
|
|
290
|
+
@classmethod
|
|
291
|
+
def _decode_identifier(cls, id_data):
|
|
292
|
+
return id_data
|
|
293
|
+
|
|
294
|
+
def _encode_identifier(self):
|
|
295
|
+
return bytes(self.identifier)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@attr.s
|
|
299
|
+
class IkeIdentificationNullMixin:
|
|
300
|
+
"""NULL identification (RFC 7619)."""
|
|
301
|
+
|
|
302
|
+
identifier: bytes = attr.ib(
|
|
303
|
+
validator=attr.validators.instance_of((bytes, bytearray)),
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
@classmethod
|
|
307
|
+
def get_id_type_ikev1(cls):
|
|
308
|
+
return None
|
|
309
|
+
|
|
310
|
+
@classmethod
|
|
311
|
+
def get_id_type_ikev2(cls):
|
|
312
|
+
return Ikev2IdType.NULL
|
|
313
|
+
|
|
314
|
+
@classmethod
|
|
315
|
+
def _decode_identifier(cls, id_data):
|
|
316
|
+
return id_data
|
|
317
|
+
|
|
318
|
+
def _encode_identifier(self):
|
|
319
|
+
return bytes(self.identifier)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@attr.s
|
|
323
|
+
class DataAttributeBase(ParsableBase):
|
|
324
|
+
"""Data attribute base parser.
|
|
325
|
+
|
|
326
|
+
.. code-block:: text
|
|
327
|
+
|
|
328
|
+
1 2 3
|
|
329
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
330
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
331
|
+
!A! Attribute Type ! AF=0 Attribute Length !
|
|
332
|
+
!F! ! AF=1 Attribute Value !
|
|
333
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
334
|
+
. AF=0 Attribute Value .
|
|
335
|
+
. AF=1 Not Transmitted .
|
|
336
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
@classmethod
|
|
340
|
+
@abc.abstractmethod
|
|
341
|
+
def _parse(cls, parsable):
|
|
342
|
+
raise NotImplementedError()
|
|
343
|
+
|
|
344
|
+
@abc.abstractmethod
|
|
345
|
+
def compose(self):
|
|
346
|
+
raise NotImplementedError()
|
|
347
|
+
|
|
348
|
+
@classmethod
|
|
349
|
+
@abc.abstractmethod
|
|
350
|
+
def get_type(cls):
|
|
351
|
+
raise NotImplementedError()
|
|
352
|
+
|
|
353
|
+
@classmethod
|
|
354
|
+
def _get_format(cls):
|
|
355
|
+
raise NotImplementedError()
|
|
356
|
+
|
|
357
|
+
@classmethod
|
|
358
|
+
def _parse_header(cls, parsable):
|
|
359
|
+
parser = ParserBinary(parsable)
|
|
360
|
+
|
|
361
|
+
parser.parse_numeric('format', 1, DataAttributeFormat)
|
|
362
|
+
if parser['format'] != cls._get_format():
|
|
363
|
+
raise InvalidType()
|
|
364
|
+
|
|
365
|
+
parser.parse_numeric_enum_coded('type', type(cls.get_type()))
|
|
366
|
+
if parser['type'] != cls.get_type():
|
|
367
|
+
raise InvalidType()
|
|
368
|
+
|
|
369
|
+
return parser
|
|
370
|
+
|
|
371
|
+
def _compose_header(self):
|
|
372
|
+
composer = ComposerBinary()
|
|
373
|
+
|
|
374
|
+
composer.compose_numeric(self._get_format().value, 1)
|
|
375
|
+
composer.compose_numeric_enum_coded(self.get_type())
|
|
376
|
+
|
|
377
|
+
return composer
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class DataAttributeFormat(enum.IntEnum):
|
|
381
|
+
"""Data attribute types."""
|
|
382
|
+
TYPE_LENGTH_VALUE = 0x00
|
|
383
|
+
TYPE_VALUE = 0x80
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@attr.s
|
|
387
|
+
class DataAttributeTypeValue(DataAttributeBase):
|
|
388
|
+
"""Data attribute type/value parser."""
|
|
389
|
+
|
|
390
|
+
@classmethod
|
|
391
|
+
@abc.abstractmethod
|
|
392
|
+
def get_type(cls):
|
|
393
|
+
raise NotImplementedError()
|
|
394
|
+
|
|
395
|
+
@classmethod
|
|
396
|
+
@abc.abstractmethod
|
|
397
|
+
def _parse(cls, parsable):
|
|
398
|
+
raise NotImplementedError()
|
|
399
|
+
|
|
400
|
+
@abc.abstractmethod
|
|
401
|
+
def compose(self):
|
|
402
|
+
raise NotImplementedError()
|
|
403
|
+
|
|
404
|
+
@classmethod
|
|
405
|
+
def _get_format(cls):
|
|
406
|
+
return DataAttributeFormat.TYPE_VALUE
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
@attr.s
|
|
410
|
+
class DataAttributeTypeValueEnumCoded(DataAttributeTypeValue):
|
|
411
|
+
"""Data attribute type/value parser where the type is an enum."""
|
|
412
|
+
|
|
413
|
+
value: typing.Any = attr.ib()
|
|
414
|
+
|
|
415
|
+
@classmethod
|
|
416
|
+
@abc.abstractmethod
|
|
417
|
+
def get_type(cls):
|
|
418
|
+
raise NotImplementedError()
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
@abc.abstractmethod
|
|
422
|
+
def _get_enum_type(cls):
|
|
423
|
+
raise NotImplementedError()
|
|
424
|
+
|
|
425
|
+
@value.validator
|
|
426
|
+
def _validate_value(self, _, value):
|
|
427
|
+
enum_type = self._get_enum_type()
|
|
428
|
+
if not isinstance(value, enum_type):
|
|
429
|
+
raise InvalidValue(value, type(self), 'value')
|
|
430
|
+
|
|
431
|
+
@classmethod
|
|
432
|
+
def _parse(cls, parsable):
|
|
433
|
+
parser = cls._parse_header(parsable)
|
|
434
|
+
|
|
435
|
+
parser.parse_numeric_enum_coded('value', cls._get_enum_type())
|
|
436
|
+
|
|
437
|
+
return cls(value=parser['value']), parser.parsed_length
|
|
438
|
+
|
|
439
|
+
def compose(self):
|
|
440
|
+
composer = self._compose_header()
|
|
441
|
+
|
|
442
|
+
composer.compose_numeric_enum_coded(self.value)
|
|
443
|
+
|
|
444
|
+
return composer.composed_bytes
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@attr.s
|
|
448
|
+
class DataAttributeKeyLength(DataAttributeTypeValue):
|
|
449
|
+
"""Key Length transform attribute (TV format).
|
|
450
|
+
|
|
451
|
+
The Key Length attribute has the following format:
|
|
452
|
+
|
|
453
|
+
0 1 2 3
|
|
454
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
455
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
456
|
+
|A| Attribute Type | Key Length (in bits) |
|
|
457
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
458
|
+
|
|
459
|
+
:ivar key_length: Key length in bits
|
|
460
|
+
"""
|
|
461
|
+
|
|
462
|
+
value: int = attr.ib(validator=attr.validators.and_(
|
|
463
|
+
attr.validators.instance_of(int),
|
|
464
|
+
attr.validators.ge(0),
|
|
465
|
+
attr.validators.lt(2**64)
|
|
466
|
+
))
|
|
467
|
+
|
|
468
|
+
@classmethod
|
|
469
|
+
@abc.abstractmethod
|
|
470
|
+
def get_type(cls):
|
|
471
|
+
raise NotImplementedError()
|
|
472
|
+
|
|
473
|
+
@classmethod
|
|
474
|
+
def _parse(cls, parsable):
|
|
475
|
+
parser = cls._parse_header(parsable)
|
|
476
|
+
parser.parse_numeric('value', 2)
|
|
477
|
+
|
|
478
|
+
return cls(value=parser['value']), parser.parsed_length
|
|
479
|
+
|
|
480
|
+
def compose(self):
|
|
481
|
+
composer = self._compose_header()
|
|
482
|
+
|
|
483
|
+
composer.compose_numeric(self.value, 2)
|
|
484
|
+
|
|
485
|
+
return composer.composed_bytes
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@attr.s
|
|
489
|
+
class DataAttributeLength(DataAttributeBase):
|
|
490
|
+
"""Length transform attribute (TLV format).
|
|
491
|
+
|
|
492
|
+
The Key Length attribute has the following format:
|
|
493
|
+
|
|
494
|
+
0 1 2 3
|
|
495
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
496
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
497
|
+
|A| Attribute Type | Key Length (in bits) |
|
|
498
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
499
|
+
|
|
500
|
+
:ivar key_length: Key length in bits
|
|
501
|
+
"""
|
|
502
|
+
|
|
503
|
+
value: int = attr.ib(validator=attr.validators.and_(
|
|
504
|
+
attr.validators.instance_of(int),
|
|
505
|
+
attr.validators.ge(0),
|
|
506
|
+
attr.validators.lt(2**64)
|
|
507
|
+
))
|
|
508
|
+
|
|
509
|
+
@classmethod
|
|
510
|
+
@abc.abstractmethod
|
|
511
|
+
def get_type(cls):
|
|
512
|
+
raise NotImplementedError()
|
|
513
|
+
|
|
514
|
+
@classmethod
|
|
515
|
+
@abc.abstractmethod
|
|
516
|
+
def _get_size(cls):
|
|
517
|
+
raise NotImplementedError()
|
|
518
|
+
|
|
519
|
+
@classmethod
|
|
520
|
+
def _get_format(cls):
|
|
521
|
+
return DataAttributeFormat.TYPE_VALUE
|
|
522
|
+
|
|
523
|
+
@classmethod
|
|
524
|
+
def _parse(cls, parsable):
|
|
525
|
+
parser = cls._parse_header(parsable)
|
|
526
|
+
|
|
527
|
+
if parser['format'] == DataAttributeFormat.TYPE_LENGTH_VALUE:
|
|
528
|
+
parser.parse_numeric('size', 2)
|
|
529
|
+
parser.parse_numeric('value', parser['size'])
|
|
530
|
+
else:
|
|
531
|
+
parser.parse_numeric('value', cls._get_size())
|
|
532
|
+
|
|
533
|
+
return cls(value=parser['value']), parser.parsed_length
|
|
534
|
+
|
|
535
|
+
def compose(self):
|
|
536
|
+
composer = self._compose_header()
|
|
537
|
+
|
|
538
|
+
if self._get_format() == DataAttributeFormat.TYPE_LENGTH_VALUE:
|
|
539
|
+
composer.compose_numeric(self._get_size(), 2)
|
|
540
|
+
composer.compose_numeric(self.value, self._get_size())
|
|
541
|
+
else:
|
|
542
|
+
composer.compose_numeric(self.value, self._get_size())
|
|
543
|
+
|
|
544
|
+
return composer.composed_bytes
|