CryptoParser 1.2.1__tar.gz → 1.4.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.2.1 → cryptoparser-1.4.0}/.gitignore +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.gitlab-ci.yml +22 -16
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.pylintrc +1 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CHANGELOG.rst +47 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/PKG-INFO +4 -3
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/SOURCES.txt +7 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/requires.txt +3 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/top_level.txt +2 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/PKG-INFO +4 -3
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/__setup__.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/base.py +7 -8
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/classes.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/exception.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/field.py +1 -2
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/parse.py +7 -8
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/utils.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/x509.py +58 -2
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/dnsrec/record.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/dnsrec/txt.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/parse.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/version.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/ikev1.py +5 -5
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/ikev2.py +149 -8
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/isakmp.py +29 -15
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/version.py +15 -21
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/key.py +5 -6
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/record.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/subprotocol.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/version.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/algorithm.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/ciphersuite.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/extension.py +19 -20
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/grease.py +1 -2
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/ldap.py +1 -2
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/mysql.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/openvpn.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/postgresql.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/rdp.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/record.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/subprotocol.py +285 -23
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/version.py +0 -1
- cryptoparser-1.4.0/cryptoparser.spec +73 -0
- cryptoparser-1.4.0/debian/changelog +31 -0
- cryptoparser-1.4.0/debian/control +31 -0
- cryptoparser-1.4.0/debian/copyright +16 -0
- cryptoparser-1.4.0/debian/rules +7 -0
- cryptoparser-1.4.0/debian/source/format +1 -0
- cryptoparser-1.4.0/debian/watch +3 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/features.rst +1 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/pyproject.toml +9 -32
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/classes.py +10 -11
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_algorithm.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_base.py +3 -4
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_classes.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_exception.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_field.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_parse.py +2 -3
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_utils.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_x509.py +20 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/dnsrec/test_record.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/dnsrec/test_txt.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/classes.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/test_version.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/classes.py +68 -4
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev1_payload.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev1_sa.py +0 -1
- cryptoparser-1.4.0/test/ike/test_ikev2_notify.py +667 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev2_payload.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev2_sa.py +22 -11
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_isakmp.py +55 -13
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_version.py +24 -18
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_ciphersuites.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_key.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_record.py +1 -2
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_subprotocol.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_version.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/classes.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_alert.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_application_data.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_change_cipher_spec.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_ciphersuite.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_extension.py +1 -2
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_grease.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_handshake.py +184 -4
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_ldap.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_mysql.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_openvpn.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_postgresql.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_rdp.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_record.py +0 -1
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_version.py +0 -1
- cryptoparser-1.2.1/.flake8 +0 -2
- cryptoparser-1.2.1/test/ike/test_ikev2_notify.py +0 -376
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.coveragerc +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.gitmodules +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.readthedocs.yaml +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CONTRIBUTING.rst +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/dependency_links.txt +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/LICENSE.txt +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/MANIFEST.in +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/README.rst +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/dnsrec/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/header.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/common.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/.gitignore +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/changelog.rst +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/conf.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/development.rst +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/index.rst +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/setup.cfg +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/setup.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/ecc256.badssl.com.pem +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/rsa8192.badssl.com.pem +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/rsa8192.badssl.com_certificate.crt +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/rsa8192.badssl.com_root_ca.crt +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/snakeoil_cert.pem +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/dnsrec/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/test_header.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/__init__.py +0 -0
- {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/__init__.py +0 -0
|
@@ -6,62 +6,70 @@ stages:
|
|
|
6
6
|
- deploy
|
|
7
7
|
|
|
8
8
|
before_script:
|
|
9
|
-
- pip install
|
|
9
|
+
- pip install uv
|
|
10
|
+
- uv pip install --system .[tests]
|
|
10
11
|
|
|
11
12
|
variables:
|
|
12
13
|
GIT_SUBMODULE_DEPTH: 1
|
|
13
14
|
GIT_SUBMODULE_STRATEGY: recursive
|
|
14
15
|
PYTHONPATH: "submodules/cryptodatahub"
|
|
15
16
|
|
|
17
|
+
.test:
|
|
18
|
+
script:
|
|
19
|
+
- coverage run -m unittest discover -v
|
|
20
|
+
- coverage report
|
|
21
|
+
|
|
16
22
|
pylint:
|
|
17
23
|
image: python:3.14-slim
|
|
18
24
|
stage: earlytest
|
|
19
|
-
script:
|
|
25
|
+
script:
|
|
26
|
+
- uv pip install --system pylint
|
|
27
|
+
- pylint --rcfile .pylintrc cryptoparser docs test
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
ruff:
|
|
22
30
|
image: python:3.14-slim
|
|
23
31
|
stage: earlytest
|
|
24
|
-
script:
|
|
32
|
+
script: uvx ruff check cryptoparser docs test
|
|
25
33
|
|
|
26
34
|
python314:
|
|
35
|
+
extends: .test
|
|
27
36
|
image: python:3.14-slim
|
|
28
37
|
stage: earlytest
|
|
29
|
-
script: tox -e py314
|
|
30
38
|
|
|
31
39
|
python39:
|
|
40
|
+
extends: .test
|
|
32
41
|
image: python:3.9-slim
|
|
33
42
|
stage: fulltest
|
|
34
|
-
script: tox -e py39
|
|
35
43
|
|
|
36
44
|
python310:
|
|
45
|
+
extends: .test
|
|
37
46
|
image: python:3.10-slim
|
|
38
47
|
stage: fulltest
|
|
39
|
-
script: tox -e py310
|
|
40
48
|
|
|
41
49
|
python311:
|
|
50
|
+
extends: .test
|
|
42
51
|
image: python:3.11-slim
|
|
43
52
|
stage: fulltest
|
|
44
|
-
script: tox -e py311
|
|
45
53
|
|
|
46
54
|
python312:
|
|
55
|
+
extends: .test
|
|
47
56
|
image: python:3.12-slim
|
|
48
57
|
stage: fulltest
|
|
49
|
-
script: tox -e py312
|
|
50
58
|
|
|
51
59
|
python313:
|
|
60
|
+
extends: .test
|
|
52
61
|
image: python:3.13-slim
|
|
53
62
|
stage: fulltest
|
|
54
|
-
script: tox -e py313
|
|
55
63
|
|
|
56
64
|
pythonrc:
|
|
65
|
+
extends: .test
|
|
57
66
|
image: python:3.15-rc-slim
|
|
58
67
|
stage: fulltest
|
|
59
|
-
script: tox -e py315
|
|
60
68
|
|
|
61
69
|
pypy3:
|
|
70
|
+
extends: .test
|
|
62
71
|
image: pypy:3-slim
|
|
63
72
|
stage: fulltest
|
|
64
|
-
script: tox -e pypy3
|
|
65
73
|
|
|
66
74
|
coveralls:
|
|
67
75
|
image: python:3.12-slim
|
|
@@ -75,9 +83,7 @@ coveralls:
|
|
|
75
83
|
PYTHONPATH: "submodules/cryptodatahub"
|
|
76
84
|
stage: deploy
|
|
77
85
|
script:
|
|
78
|
-
- pip install coveralls
|
|
79
|
-
- pip install .
|
|
80
|
-
- pip install .[tests]
|
|
86
|
+
- uv pip install --system coveralls
|
|
81
87
|
- coverage run -m unittest -v -f
|
|
82
88
|
- coveralls
|
|
83
89
|
only:
|
|
@@ -86,7 +92,7 @@ coveralls:
|
|
|
86
92
|
|
|
87
93
|
obs:
|
|
88
94
|
image:
|
|
89
|
-
name: coroner/python_obs:1.
|
|
95
|
+
name: coroner/python_obs:1.2.5
|
|
90
96
|
pull_policy: always
|
|
91
97
|
stage: deploy
|
|
92
98
|
variables:
|
|
@@ -2,6 +2,53 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
------------------
|
|
6
|
+
1.4.0 - 2026-07-17
|
|
7
|
+
------------------
|
|
8
|
+
|
|
9
|
+
Features
|
|
10
|
+
========
|
|
11
|
+
|
|
12
|
+
- IKE (``ike``)
|
|
13
|
+
|
|
14
|
+
- add getter for multiple payloads with the same type (#93)
|
|
15
|
+
- add IKEv2 notify payload parsing for protocol extensions (#93)
|
|
16
|
+
|
|
17
|
+
- NAT detection source IP and destination IP
|
|
18
|
+
- set window size
|
|
19
|
+
- use transport mode
|
|
20
|
+
- HTTP certificate lookup supported
|
|
21
|
+
- signature hash algorithms
|
|
22
|
+
- intermediate exchange supported
|
|
23
|
+
- use PPK
|
|
24
|
+
- redirect supported
|
|
25
|
+
- IKEv2 fragmentation supported
|
|
26
|
+
- childless IKEv2 supported
|
|
27
|
+
|
|
28
|
+
------------------
|
|
29
|
+
1.3.0 - 2026-06-15
|
|
30
|
+
------------------
|
|
31
|
+
|
|
32
|
+
Features
|
|
33
|
+
========
|
|
34
|
+
|
|
35
|
+
- Generic
|
|
36
|
+
|
|
37
|
+
- add Debian and RPM packaging (#102)
|
|
38
|
+
|
|
39
|
+
- TLS (``tls``)
|
|
40
|
+
|
|
41
|
+
- add JA4 tag generation for the client hello message (#100)
|
|
42
|
+
- add JA4X tag generation for X.509 certificates (#101)
|
|
43
|
+
- add certificate-related messages for protocol version 1.3 (#94)
|
|
44
|
+
|
|
45
|
+
Notable fixes
|
|
46
|
+
=============
|
|
47
|
+
|
|
48
|
+
- IKE (``ike``)
|
|
49
|
+
|
|
50
|
+
- make IKEv2 transform key length optional for fixed-key ciphers (#99)
|
|
51
|
+
|
|
5
52
|
------------------
|
|
6
53
|
1.2.1 - 2026-06-02
|
|
7
54
|
------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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>
|
|
@@ -13,7 +13,6 @@ Project-URL: Source, https://gitlab.com/coroner/cryptoparser
|
|
|
13
13
|
Keywords: ssl,tls,gost,ja3,ldap,rdp,ssh,hsts,dns,ike
|
|
14
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Environment :: Console
|
|
16
|
-
Classifier: Framework :: tox
|
|
17
16
|
Classifier: Intended Audience :: Information Technology
|
|
18
17
|
Classifier: Intended Audience :: Science/Research
|
|
19
18
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -40,13 +39,15 @@ Description-Content-Type: text/x-rst
|
|
|
40
39
|
License-File: LICENSE.txt
|
|
41
40
|
Requires-Dist: asn1crypto
|
|
42
41
|
Requires-Dist: attrs
|
|
43
|
-
Requires-Dist: cryptodatahub==1.
|
|
42
|
+
Requires-Dist: cryptodatahub==1.4.0
|
|
44
43
|
Requires-Dist: urllib3
|
|
45
44
|
Provides-Extra: tests
|
|
46
45
|
Requires-Dist: pyfakefs; extra == "tests"
|
|
46
|
+
Requires-Dist: coverage; extra == "tests"
|
|
47
47
|
Provides-Extra: docs
|
|
48
48
|
Requires-Dist: sphinx; extra == "docs"
|
|
49
49
|
Requires-Dist: sphinx-sitemap; extra == "docs"
|
|
50
|
+
Requires-Dist: docutils; extra == "docs"
|
|
50
51
|
Dynamic: license-file
|
|
51
52
|
|
|
52
53
|
.. image:: https://gitlab.com/coroner/cryptoparser/badges/master/pipeline.svg
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
.coveragerc
|
|
2
|
-
.flake8
|
|
3
2
|
.gitignore
|
|
4
3
|
.gitlab-ci.yml
|
|
5
4
|
.gitmodules
|
|
@@ -10,6 +9,7 @@ CONTRIBUTING.rst
|
|
|
10
9
|
LICENSE.txt
|
|
11
10
|
MANIFEST.in
|
|
12
11
|
README.rst
|
|
12
|
+
cryptoparser.spec
|
|
13
13
|
pyproject.toml
|
|
14
14
|
setup.py
|
|
15
15
|
CryptoParser.egg-info/PKG-INFO
|
|
@@ -58,6 +58,12 @@ cryptoparser/tls/rdp.py
|
|
|
58
58
|
cryptoparser/tls/record.py
|
|
59
59
|
cryptoparser/tls/subprotocol.py
|
|
60
60
|
cryptoparser/tls/version.py
|
|
61
|
+
debian/changelog
|
|
62
|
+
debian/control
|
|
63
|
+
debian/copyright
|
|
64
|
+
debian/rules
|
|
65
|
+
debian/watch
|
|
66
|
+
debian/source/format
|
|
61
67
|
docs/.gitignore
|
|
62
68
|
docs/changelog.rst
|
|
63
69
|
docs/conf.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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>
|
|
@@ -13,7 +13,6 @@ Project-URL: Source, https://gitlab.com/coroner/cryptoparser
|
|
|
13
13
|
Keywords: ssl,tls,gost,ja3,ldap,rdp,ssh,hsts,dns,ike
|
|
14
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Environment :: Console
|
|
16
|
-
Classifier: Framework :: tox
|
|
17
16
|
Classifier: Intended Audience :: Information Technology
|
|
18
17
|
Classifier: Intended Audience :: Science/Research
|
|
19
18
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -40,13 +39,15 @@ Description-Content-Type: text/x-rst
|
|
|
40
39
|
License-File: LICENSE.txt
|
|
41
40
|
Requires-Dist: asn1crypto
|
|
42
41
|
Requires-Dist: attrs
|
|
43
|
-
Requires-Dist: cryptodatahub==1.
|
|
42
|
+
Requires-Dist: cryptodatahub==1.4.0
|
|
44
43
|
Requires-Dist: urllib3
|
|
45
44
|
Provides-Extra: tests
|
|
46
45
|
Requires-Dist: pyfakefs; extra == "tests"
|
|
46
|
+
Requires-Dist: coverage; extra == "tests"
|
|
47
47
|
Provides-Extra: docs
|
|
48
48
|
Requires-Dist: sphinx; extra == "docs"
|
|
49
49
|
Requires-Dist: sphinx-sitemap; extra == "docs"
|
|
50
|
+
Requires-Dist: docutils; extra == "docs"
|
|
50
51
|
Dynamic: license-file
|
|
51
52
|
|
|
52
53
|
.. image:: https://gitlab.com/coroner/cryptoparser/badges/master/pipeline.svg
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# pylint: disable=too-many-lines
|
|
4
3
|
|
|
5
4
|
import abc
|
|
@@ -14,7 +13,7 @@ import ipaddress
|
|
|
14
13
|
try:
|
|
15
14
|
from collections.abc import MutableSequence # only works on python 3.3+
|
|
16
15
|
except ImportError: # pragma: no cover
|
|
17
|
-
from collections import MutableSequence # pylint: disable=deprecated-class
|
|
16
|
+
from collections.abc import MutableSequence # pylint: disable=deprecated-class
|
|
18
17
|
|
|
19
18
|
from collections import OrderedDict
|
|
20
19
|
|
|
@@ -49,7 +48,7 @@ _default.default = json.JSONEncoder().default
|
|
|
49
48
|
json.JSONEncoder.default = _default
|
|
50
49
|
|
|
51
50
|
|
|
52
|
-
class SerializableTextEncoder
|
|
51
|
+
class SerializableTextEncoder:
|
|
53
52
|
def __call__(self, obj, level):
|
|
54
53
|
if isinstance(obj, str):
|
|
55
54
|
string_result = obj
|
|
@@ -59,7 +58,7 @@ class SerializableTextEncoder():
|
|
|
59
58
|
return False, string_result
|
|
60
59
|
|
|
61
60
|
|
|
62
|
-
class Serializable
|
|
61
|
+
class Serializable: # pylint: disable=too-few-public-methods
|
|
63
62
|
_MARKDOWN_RESULT_STRING_CLASSES = (
|
|
64
63
|
ipaddress.IPv4Network,
|
|
65
64
|
ipaddress.IPv6Network,
|
|
@@ -367,7 +366,7 @@ class VariantParsableExact(VariantParsableBase):
|
|
|
367
366
|
|
|
368
367
|
|
|
369
368
|
@attr.s
|
|
370
|
-
class VectorParamBase
|
|
369
|
+
class VectorParamBase: # pylint: disable=too-few-public-methods
|
|
371
370
|
min_byte_num = attr.ib(validator=attr.validators.instance_of(int))
|
|
372
371
|
max_byte_num = attr.ib(validator=attr.validators.instance_of(int))
|
|
373
372
|
item_num_size = attr.ib(init=False, validator=attr.validators.instance_of(int))
|
|
@@ -863,7 +862,7 @@ class StringEnumParsableBase(ParsableBaseNoABC):
|
|
|
863
862
|
return self._asdict().encode('ascii')
|
|
864
863
|
|
|
865
864
|
def _asdict(self):
|
|
866
|
-
return
|
|
865
|
+
return self.value.code
|
|
867
866
|
|
|
868
867
|
|
|
869
868
|
class StringEnumParsable(StringEnumParsableBase):
|
|
@@ -946,7 +945,7 @@ class ProtocolVersionMajorMinorBase(ProtocolVersionBase):
|
|
|
946
945
|
|
|
947
946
|
|
|
948
947
|
@attr.s
|
|
949
|
-
class ListParamParsable
|
|
948
|
+
class ListParamParsable: # pylint: disable=too-few-public-methods
|
|
950
949
|
item_class = attr.ib(validator=attr.validators.instance_of(type))
|
|
951
950
|
fallback_class = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(type)))
|
|
952
951
|
separator_class = attr.ib(attr.validators.instance_of(ParsableBase))
|
|
@@ -994,7 +993,7 @@ class ListParsable(ArrayBase):
|
|
|
994
993
|
class OpaqueEnumParsable(Vector):
|
|
995
994
|
@classmethod
|
|
996
995
|
def _parse(cls, parsable):
|
|
997
|
-
opaque, parsed_length = super(
|
|
996
|
+
opaque, parsed_length = super()._parse(parsable)
|
|
998
997
|
code = b''.join([bytes((opaque_item,)) for opaque_item in opaque]).decode(cls.get_encoding())
|
|
999
998
|
|
|
1000
999
|
try:
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# pylint: disable=too-many-lines
|
|
4
3
|
|
|
5
4
|
import abc
|
|
@@ -540,7 +539,7 @@ class FieldValueComponentPercent(FieldValueComponentNumber):
|
|
|
540
539
|
|
|
541
540
|
|
|
542
541
|
@attr.s
|
|
543
|
-
class FieldValueComponentStringEnumParams
|
|
542
|
+
class FieldValueComponentStringEnumParams:
|
|
544
543
|
code = attr.ib(validator=attr.validators.instance_of(str))
|
|
545
544
|
|
|
546
545
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# pylint: disable=too-many-lines
|
|
4
3
|
|
|
5
4
|
import abc
|
|
@@ -19,7 +18,7 @@ from cryptoparser.common.exception import InvalidType, NotEnoughData, TooMuchDat
|
|
|
19
18
|
import cryptoparser.common.utils
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
class ParsableBaseNoABC
|
|
21
|
+
class ParsableBaseNoABC:
|
|
23
22
|
@classmethod
|
|
24
23
|
def parse_mutable(cls, parsable):
|
|
25
24
|
parsed_object, parsed_length = cls._parse(parsable)
|
|
@@ -96,7 +95,7 @@ class ParserBase(collections.abc.Mapping):
|
|
|
96
95
|
validator=attr.validators.instance_of((bytes, bytearray))
|
|
97
96
|
)
|
|
98
97
|
_parsed_length: int = attr.ib(init=False, default=0)
|
|
99
|
-
_parsed_values:
|
|
98
|
+
_parsed_values: dict[str, typing.Any] = attr.ib(init=False, default=None)
|
|
100
99
|
|
|
101
100
|
def __attrs_post_init__(self):
|
|
102
101
|
if self._parsed_values is None:
|
|
@@ -165,7 +164,7 @@ class ParserBase(collections.abc.Mapping):
|
|
|
165
164
|
value = self._parsable[self._parsed_length:self._parsed_length + parsable_length]
|
|
166
165
|
try:
|
|
167
166
|
value = value.decode(encoding)
|
|
168
|
-
if converter
|
|
167
|
+
if converter is not str:
|
|
169
168
|
value = converter(value)
|
|
170
169
|
self._parsed_values[name] = value
|
|
171
170
|
except UnicodeError as e:
|
|
@@ -760,8 +759,8 @@ class ParserBinary(ParserBase):
|
|
|
760
759
|
|
|
761
760
|
|
|
762
761
|
@attr.s
|
|
763
|
-
class ComposerBase
|
|
764
|
-
_composed = attr.ib(init=False, default=
|
|
762
|
+
class ComposerBase:
|
|
763
|
+
_composed = attr.ib(init=False, default=b'')
|
|
765
764
|
|
|
766
765
|
@property
|
|
767
766
|
def composed(self):
|
|
@@ -795,7 +794,7 @@ class ComposerText(ComposerBase):
|
|
|
795
794
|
self._encoding = encoding
|
|
796
795
|
|
|
797
796
|
def _compose_numeric_array(self, values, separator):
|
|
798
|
-
composed_str =
|
|
797
|
+
composed_str = ''
|
|
799
798
|
|
|
800
799
|
for value in values:
|
|
801
800
|
composed_str += f'{value:d}{separator}'
|
|
@@ -969,7 +968,7 @@ class ComposerBinary(ComposerBase):
|
|
|
969
968
|
self.compose_numeric(len(composed), item_size)
|
|
970
969
|
self._composed += composed
|
|
971
970
|
|
|
972
|
-
def compose_parsable_array(self, values, separator=
|
|
971
|
+
def compose_parsable_array(self, values, separator=b''):
|
|
973
972
|
self._composed += separator.join(map(lambda item: item.compose(), values))
|
|
974
973
|
|
|
975
974
|
def compose_bytes(self, value, item_size, converter=bytearray):
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
|
|
4
3
|
import collections
|
|
5
4
|
import datetime
|
|
6
5
|
import enum
|
|
6
|
+
import hashlib
|
|
7
7
|
|
|
8
8
|
import attr
|
|
9
9
|
|
|
@@ -19,7 +19,7 @@ from cryptoparser.common.base import (
|
|
|
19
19
|
VectorParamParsable,
|
|
20
20
|
VectorParsable,
|
|
21
21
|
)
|
|
22
|
-
from cryptoparser.common.parse import ComposerBinary, ParsableBase, ParserBinary
|
|
22
|
+
from cryptoparser.common.parse import ComposerBinary, ComposerText, ParsableBase, ParserBinary
|
|
23
23
|
|
|
24
24
|
from cryptoparser.tls.algorithm import TlsSignatureAndHashAlgorithm, TlsSignatureAndHashAlgorithmFactory
|
|
25
25
|
|
|
@@ -106,7 +106,21 @@ class SignedCertificateTimestampList(VectorParsable):
|
|
|
106
106
|
)
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
@attr.s(frozen=True)
|
|
110
|
+
class TlsJA4XFingerprint(Serializable):
|
|
111
|
+
fingerprint = attr.ib(validator=attr.validators.instance_of(str))
|
|
112
|
+
fingerprint_raw = attr.ib(validator=attr.validators.instance_of(str))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@attr.s(eq=False, init=False, frozen=True)
|
|
109
116
|
class PublicKeyX509(PublicKeyX509Base):
|
|
117
|
+
ja4x = attr.ib(init=False, default=None, metadata={'human_readable_name': 'JA4X'})
|
|
118
|
+
|
|
119
|
+
def __init__(self, certificate):
|
|
120
|
+
super().__init__(certificate)
|
|
121
|
+
|
|
122
|
+
object.__setattr__(self, 'ja4x', self._ja4x())
|
|
123
|
+
|
|
110
124
|
@property
|
|
111
125
|
def signed_certificate_timestamps(self):
|
|
112
126
|
for extension in self._certificate['tbs_certificate']['extensions']:
|
|
@@ -116,9 +130,51 @@ class PublicKeyX509(PublicKeyX509Base):
|
|
|
116
130
|
|
|
117
131
|
return SignedCertificateTimestampList([])
|
|
118
132
|
|
|
133
|
+
@staticmethod
|
|
134
|
+
def _ja4x_sha256(oid_hexes):
|
|
135
|
+
composer = ComposerText()
|
|
136
|
+
composer.compose_string_array(oid_hexes, ',')
|
|
137
|
+
return hashlib.sha256(composer.composed).hexdigest()[:12]
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def _ja4x_relative_distinguished_name_oid_hexes(name):
|
|
141
|
+
return [
|
|
142
|
+
attribute['type'].contents.hex()
|
|
143
|
+
for relative_distinguished_name in name.chosen
|
|
144
|
+
for attribute in relative_distinguished_name
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
def _ja4x(self):
|
|
148
|
+
tbs_certificate = self._certificate['tbs_certificate']
|
|
149
|
+
issuer_oid_hexes = self._ja4x_relative_distinguished_name_oid_hexes(tbs_certificate['issuer'])
|
|
150
|
+
subject_oid_hexes = self._ja4x_relative_distinguished_name_oid_hexes(tbs_certificate['subject'])
|
|
151
|
+
extension_oid_hexes = [
|
|
152
|
+
extension['extn_id'].contents.hex()
|
|
153
|
+
for extension in tbs_certificate['extensions']
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
fingerprint_composer = ComposerText()
|
|
157
|
+
fingerprint_composer.compose_string_array([
|
|
158
|
+
self._ja4x_sha256(issuer_oid_hexes),
|
|
159
|
+
self._ja4x_sha256(subject_oid_hexes),
|
|
160
|
+
self._ja4x_sha256(extension_oid_hexes),
|
|
161
|
+
], '_')
|
|
162
|
+
|
|
163
|
+
raw_composer = ComposerText()
|
|
164
|
+
raw_composer.compose_string_array(issuer_oid_hexes, ',')
|
|
165
|
+
for oid_hexes in (subject_oid_hexes, extension_oid_hexes):
|
|
166
|
+
raw_composer.compose_separator('_')
|
|
167
|
+
raw_composer.compose_string_array(oid_hexes, ',')
|
|
168
|
+
|
|
169
|
+
return TlsJA4XFingerprint(
|
|
170
|
+
fingerprint=fingerprint_composer.composed.decode('ascii'),
|
|
171
|
+
fingerprint_raw=raw_composer.composed.decode('ascii'),
|
|
172
|
+
)
|
|
173
|
+
|
|
119
174
|
def _asdict(self):
|
|
120
175
|
dict_value = super()._asdict()
|
|
121
176
|
|
|
122
177
|
return collections.OrderedDict(list(dict_value.items()) + [
|
|
178
|
+
('ja4x', self.ja4x),
|
|
123
179
|
('signed_certificate_timestamps', self.signed_certificate_timestamps),
|
|
124
180
|
])
|
|
@@ -226,7 +226,7 @@ class Ikev1PayloadTransform(Ikev1PayloadBase):
|
|
|
226
226
|
"""
|
|
227
227
|
|
|
228
228
|
transform_id: Ikev1TransformId = attr.ib(validator=attr.validators.instance_of(Ikev1TransformId))
|
|
229
|
-
attributes:
|
|
229
|
+
attributes: list[DataAttributeBase] = attr.ib(
|
|
230
230
|
validator=attr.validators.deep_iterable(
|
|
231
231
|
member_validator=attr.validators.instance_of(DataAttributeBase),
|
|
232
232
|
)
|
|
@@ -310,10 +310,10 @@ class Ikev1PayloadProposal(Ikev1PayloadBase):
|
|
|
310
310
|
"""
|
|
311
311
|
|
|
312
312
|
protocol_id: Ikev1ProtocolId = attr.ib(validator=attr.validators.instance_of(Ikev1ProtocolId))
|
|
313
|
-
transforms:
|
|
313
|
+
transforms: list[Ikev1PayloadTransform] = attr.ib(validator=attr.validators.deep_iterable(
|
|
314
314
|
member_validator=attr.validators.instance_of(Ikev1PayloadTransform),
|
|
315
315
|
))
|
|
316
|
-
spi: bytes = attr.ib(default=
|
|
316
|
+
spi: bytes = attr.ib(default=b'', converter=bytes, validator=attr.validators.instance_of(bytes))
|
|
317
317
|
next_payload: typing.Optional[Ikev1PayloadType] = attr.ib(
|
|
318
318
|
init=False,
|
|
319
319
|
default=None,
|
|
@@ -409,10 +409,10 @@ class Ikev1PayloadSecurityAssociation(Ikev1PayloadBase):
|
|
|
409
409
|
"""
|
|
410
410
|
|
|
411
411
|
doi: Ikev1Doi = attr.ib(validator=attr.validators.instance_of(Ikev1Doi))
|
|
412
|
-
situation:
|
|
412
|
+
situation: list[Ikev1Situation] = attr.ib(validator=attr.validators.deep_iterable(
|
|
413
413
|
member_validator=attr.validators.instance_of(Ikev1Situation),
|
|
414
414
|
))
|
|
415
|
-
proposals:
|
|
415
|
+
proposals: list[Ikev1PayloadProposal] = attr.ib(validator=attr.validators.deep_iterable(
|
|
416
416
|
member_validator=attr.validators.instance_of(Ikev1PayloadProposal),
|
|
417
417
|
))
|
|
418
418
|
|