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.
Files changed (129) hide show
  1. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CHANGELOG.rst +30 -0
  2. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/PKG-INFO +5 -5
  3. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/requires.txt +1 -1
  4. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/top_level.txt +2 -1
  5. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/PKG-INFO +5 -5
  6. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/README.rst +3 -3
  7. cryptoparser-1.5.0/cryptoparser/ike/common.py +544 -0
  8. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/ikev1.py +348 -15
  9. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/ikev2.py +656 -20
  10. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/isakmp.py +123 -48
  11. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser.spec +19 -3
  12. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/changelog +19 -0
  13. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/rules +1 -1
  14. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/features.rst +7 -0
  15. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/pyproject.toml +2 -2
  16. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev1_payload.py +329 -37
  17. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev2_notify.py +8 -2
  18. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev2_payload.py +520 -34
  19. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_isakmp.py +104 -9
  20. cryptoparser-1.4.0/cryptoparser/ike/common.py +0 -236
  21. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.coveragerc +0 -0
  22. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.gitignore +0 -0
  23. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.gitlab-ci.yml +0 -0
  24. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.gitmodules +0 -0
  25. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.pylintrc +0 -0
  26. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/.readthedocs.yaml +0 -0
  27. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CONTRIBUTING.rst +0 -0
  28. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/SOURCES.txt +0 -0
  29. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/CryptoParser.egg-info/dependency_links.txt +0 -0
  30. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/LICENSE.txt +0 -0
  31. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/MANIFEST.in +0 -0
  32. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/__init__.py +0 -0
  33. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/__setup__.py +0 -0
  34. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/__init__.py +0 -0
  35. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/base.py +0 -0
  36. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/classes.py +0 -0
  37. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/exception.py +0 -0
  38. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/field.py +0 -0
  39. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/parse.py +0 -0
  40. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/utils.py +0 -0
  41. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/common/x509.py +0 -0
  42. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/dnsrec/__init__.py +0 -0
  43. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/dnsrec/record.py +0 -0
  44. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/dnsrec/txt.py +0 -0
  45. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/__init__.py +0 -0
  46. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/header.py +0 -0
  47. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/parse.py +0 -0
  48. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/httpx/version.py +0 -0
  49. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/__init__.py +0 -0
  50. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ike/version.py +0 -0
  51. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/__init__.py +0 -0
  52. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/key.py +0 -0
  53. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/record.py +0 -0
  54. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/subprotocol.py +0 -0
  55. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/ssh/version.py +0 -0
  56. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/__init__.py +0 -0
  57. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/algorithm.py +0 -0
  58. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/ciphersuite.py +0 -0
  59. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/extension.py +0 -0
  60. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/grease.py +0 -0
  61. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/ldap.py +0 -0
  62. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/mysql.py +0 -0
  63. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/openvpn.py +0 -0
  64. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/postgresql.py +0 -0
  65. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/rdp.py +0 -0
  66. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/record.py +0 -0
  67. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/subprotocol.py +0 -0
  68. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/cryptoparser/tls/version.py +0 -0
  69. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/control +0 -0
  70. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/copyright +0 -0
  71. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/source/format +0 -0
  72. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/debian/watch +0 -0
  73. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/.gitignore +0 -0
  74. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/changelog.rst +0 -0
  75. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/conf.py +0 -0
  76. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/development.rst +0 -0
  77. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/docs/index.rst +0 -0
  78. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/setup.cfg +0 -0
  79. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/setup.py +0 -0
  80. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/__init__.py +0 -0
  81. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/__init__.py +0 -0
  82. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/ecc256.badssl.com.pem +0 -0
  83. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/rsa8192.badssl.com.pem +0 -0
  84. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/rsa8192.badssl.com_certificate.crt +0 -0
  85. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/rsa8192.badssl.com_root_ca.crt +0 -0
  86. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/certs/snakeoil_cert.pem +0 -0
  87. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/classes.py +0 -0
  88. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_algorithm.py +0 -0
  89. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_base.py +0 -0
  90. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_classes.py +0 -0
  91. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_exception.py +0 -0
  92. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_field.py +0 -0
  93. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_parse.py +0 -0
  94. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_utils.py +0 -0
  95. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/common/test_x509.py +0 -0
  96. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/dnsrec/__init__.py +0 -0
  97. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/dnsrec/test_record.py +0 -0
  98. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/dnsrec/test_txt.py +0 -0
  99. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/__init__.py +0 -0
  100. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/classes.py +0 -0
  101. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/test_header.py +0 -0
  102. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/httpx/test_version.py +0 -0
  103. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/__init__.py +0 -0
  104. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/classes.py +0 -0
  105. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev1_sa.py +0 -0
  106. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_ikev2_sa.py +0 -0
  107. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ike/test_version.py +0 -0
  108. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/__init__.py +0 -0
  109. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_ciphersuites.py +0 -0
  110. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_key.py +0 -0
  111. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_record.py +0 -0
  112. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_subprotocol.py +0 -0
  113. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/ssh/test_version.py +0 -0
  114. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/__init__.py +0 -0
  115. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/classes.py +0 -0
  116. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_alert.py +0 -0
  117. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_application_data.py +0 -0
  118. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_change_cipher_spec.py +0 -0
  119. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_ciphersuite.py +0 -0
  120. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_extension.py +0 -0
  121. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_grease.py +0 -0
  122. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_handshake.py +0 -0
  123. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_ldap.py +0 -0
  124. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_mysql.py +0 -0
  125. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_openvpn.py +0 -0
  126. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_postgresql.py +0 -0
  127. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_rdp.py +0 -0
  128. {cryptoparser-1.4.0 → cryptoparser-1.5.0}/test/tls/test_record.py +0 -0
  129. {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.4.0
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.4.0
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. It
64
- is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support
65
- testing cryptographic libraries or analysing cryptography-realted settings of application servers such as
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
  asn1crypto
2
2
  attrs
3
- cryptodatahub==1.4.0
3
+ cryptodatahub==1.5.0
4
4
  urllib3
5
5
 
6
6
  [docs]
@@ -1,7 +1,8 @@
1
+ build
1
2
  cryptoparser
2
3
  debian
3
4
  dist
4
5
  docs
6
+ htmlcov
5
7
  submodules
6
8
  test
7
- tmp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CryptoParser
3
- Version: 1.4.0
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.4.0
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. It
64
- is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support
65
- testing cryptographic libraries or analysing cryptography-realted settings of application servers such as
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. It
12
- is neither a comprehensive nor a secure implementation of any cryptographic protocol. The goal is to support
13
- testing cryptographic libraries or analysing cryptography-realted settings of application servers such as
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