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.
Files changed (130) hide show
  1. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.gitignore +0 -1
  2. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.gitlab-ci.yml +22 -16
  3. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.pylintrc +1 -0
  4. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CHANGELOG.rst +47 -0
  5. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/PKG-INFO +4 -3
  6. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/SOURCES.txt +7 -1
  7. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/requires.txt +3 -1
  8. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/top_level.txt +2 -0
  9. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/PKG-INFO +4 -3
  10. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/__setup__.py +0 -1
  11. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/base.py +7 -8
  12. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/classes.py +0 -1
  13. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/exception.py +0 -1
  14. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/field.py +1 -2
  15. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/parse.py +7 -8
  16. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/utils.py +0 -1
  17. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/x509.py +58 -2
  18. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/dnsrec/record.py +0 -1
  19. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/dnsrec/txt.py +0 -1
  20. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/parse.py +0 -1
  21. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/version.py +0 -1
  22. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/ikev1.py +5 -5
  23. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/ikev2.py +149 -8
  24. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/isakmp.py +29 -15
  25. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/version.py +15 -21
  26. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/key.py +5 -6
  27. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/record.py +0 -1
  28. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/subprotocol.py +0 -1
  29. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/version.py +0 -1
  30. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/algorithm.py +0 -1
  31. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/ciphersuite.py +0 -1
  32. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/extension.py +19 -20
  33. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/grease.py +1 -2
  34. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/ldap.py +1 -2
  35. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/mysql.py +0 -1
  36. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/openvpn.py +0 -1
  37. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/postgresql.py +0 -1
  38. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/rdp.py +0 -1
  39. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/record.py +0 -1
  40. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/subprotocol.py +285 -23
  41. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/version.py +0 -1
  42. cryptoparser-1.4.0/cryptoparser.spec +73 -0
  43. cryptoparser-1.4.0/debian/changelog +31 -0
  44. cryptoparser-1.4.0/debian/control +31 -0
  45. cryptoparser-1.4.0/debian/copyright +16 -0
  46. cryptoparser-1.4.0/debian/rules +7 -0
  47. cryptoparser-1.4.0/debian/source/format +1 -0
  48. cryptoparser-1.4.0/debian/watch +3 -0
  49. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/features.rst +1 -0
  50. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/pyproject.toml +9 -32
  51. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/classes.py +10 -11
  52. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_algorithm.py +0 -1
  53. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_base.py +3 -4
  54. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_classes.py +0 -1
  55. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_exception.py +0 -1
  56. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_field.py +0 -1
  57. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_parse.py +2 -3
  58. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_utils.py +0 -1
  59. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/test_x509.py +20 -1
  60. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/dnsrec/test_record.py +0 -1
  61. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/dnsrec/test_txt.py +0 -1
  62. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/classes.py +0 -1
  63. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/test_version.py +0 -1
  64. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/classes.py +68 -4
  65. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev1_payload.py +0 -1
  66. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev1_sa.py +0 -1
  67. cryptoparser-1.4.0/test/ike/test_ikev2_notify.py +667 -0
  68. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev2_payload.py +0 -1
  69. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_ikev2_sa.py +22 -11
  70. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_isakmp.py +55 -13
  71. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/test_version.py +24 -18
  72. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_ciphersuites.py +0 -1
  73. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_key.py +0 -1
  74. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_record.py +1 -2
  75. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_subprotocol.py +0 -1
  76. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/test_version.py +0 -1
  77. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/classes.py +0 -1
  78. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_alert.py +0 -1
  79. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_application_data.py +0 -1
  80. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_change_cipher_spec.py +0 -1
  81. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_ciphersuite.py +0 -1
  82. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_extension.py +1 -2
  83. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_grease.py +0 -1
  84. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_handshake.py +184 -4
  85. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_ldap.py +0 -1
  86. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_mysql.py +0 -1
  87. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_openvpn.py +0 -1
  88. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_postgresql.py +0 -1
  89. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_rdp.py +0 -1
  90. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_record.py +0 -1
  91. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/test_version.py +0 -1
  92. cryptoparser-1.2.1/.flake8 +0 -2
  93. cryptoparser-1.2.1/test/ike/test_ikev2_notify.py +0 -376
  94. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.coveragerc +0 -0
  95. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.gitmodules +0 -0
  96. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/.readthedocs.yaml +0 -0
  97. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CONTRIBUTING.rst +0 -0
  98. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/CryptoParser.egg-info/dependency_links.txt +0 -0
  99. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/LICENSE.txt +0 -0
  100. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/MANIFEST.in +0 -0
  101. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/README.rst +0 -0
  102. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/__init__.py +0 -0
  103. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/common/__init__.py +0 -0
  104. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/dnsrec/__init__.py +0 -0
  105. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/__init__.py +0 -0
  106. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/httpx/header.py +0 -0
  107. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/__init__.py +0 -0
  108. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ike/common.py +0 -0
  109. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/ssh/__init__.py +0 -0
  110. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/cryptoparser/tls/__init__.py +0 -0
  111. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/.gitignore +0 -0
  112. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/changelog.rst +0 -0
  113. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/conf.py +0 -0
  114. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/development.rst +0 -0
  115. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/docs/index.rst +0 -0
  116. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/setup.cfg +0 -0
  117. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/setup.py +0 -0
  118. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/__init__.py +0 -0
  119. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/__init__.py +0 -0
  120. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/ecc256.badssl.com.pem +0 -0
  121. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/rsa8192.badssl.com.pem +0 -0
  122. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/rsa8192.badssl.com_certificate.crt +0 -0
  123. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/rsa8192.badssl.com_root_ca.crt +0 -0
  124. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/common/certs/snakeoil_cert.pem +0 -0
  125. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/dnsrec/__init__.py +0 -0
  126. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/__init__.py +0 -0
  127. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/httpx/test_header.py +0 -0
  128. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ike/__init__.py +0 -0
  129. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/ssh/__init__.py +0 -0
  130. {cryptoparser-1.2.1 → cryptoparser-1.4.0}/test/tls/__init__.py +0 -0
@@ -10,7 +10,6 @@
10
10
  /.coverage
11
11
 
12
12
  /.eggs
13
- /.tox
14
13
  /Pipfile
15
14
  /Pipfile.lock
16
15
  /build
@@ -6,62 +6,70 @@ stages:
6
6
  - deploy
7
7
 
8
8
  before_script:
9
- - pip install tox .[tests]
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: tox -e pylint
25
+ script:
26
+ - uv pip install --system pylint
27
+ - pylint --rcfile .pylintrc cryptoparser docs test
20
28
 
21
- pep8:
29
+ ruff:
22
30
  image: python:3.14-slim
23
31
  stage: earlytest
24
- script: tox -e pep8
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.1.2
95
+ name: coroner/python_obs:1.2.5
90
96
  pull_policy: always
91
97
  stage: deploy
92
98
  variables:
@@ -18,3 +18,4 @@ disable=
18
18
  too-many-function-args,
19
19
  too-many-ancestors,
20
20
  duplicate-code,
21
+ no-member,
@@ -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.2.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.2.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,11 +1,13 @@
1
1
  asn1crypto
2
2
  attrs
3
- cryptodatahub==1.2.1
3
+ cryptodatahub==1.4.0
4
4
  urllib3
5
5
 
6
6
  [docs]
7
7
  sphinx
8
8
  sphinx-sitemap
9
+ docutils
9
10
 
10
11
  [tests]
11
12
  pyfakefs
13
+ coverage
@@ -1,5 +1,7 @@
1
1
  cryptoparser
2
+ debian
2
3
  dist
3
4
  docs
4
5
  submodules
5
6
  test
7
+ tmp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CryptoParser
3
- Version: 1.2.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.2.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
 
4
3
  import importlib.metadata
5
4
 
@@ -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(): # pylint: disable=too-few-public-methods
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(): # pylint: disable=too-few-public-methods
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 getattr(self, 'value').code
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(): # pylint: disable=too-few-public-methods
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(OpaqueEnumParsable, cls)._parse(parsable)
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
 
4
3
 
5
4
  from cryptodatahub.common.exception import InvalidValue
@@ -1,5 +1,4 @@
1
1
  # SPDX-License-Identifier: MPL-2.0
2
- # -*- coding: utf-8 -*-
3
2
 
4
3
  import typing
5
4
 
@@ -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: typing.Dict[str, typing.Any] = attr.ib(init=False, default=None)
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 != str:
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=bytes())
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 = 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=bytearray()):
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,5 +1,4 @@
1
1
  # SPDX-License-Identifier: MPL-2.0
2
- # -*- coding: utf-8 -*-
3
2
 
4
3
  import binascii
5
4
  import inspect
@@ -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
  ])
@@ -1,5 +1,4 @@
1
1
  # SPDX-License-Identifier: MPL-2.0
2
- # -*- coding: utf-8 -*-
3
2
 
4
3
  import abc
5
4
  import collections
@@ -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
@@ -1,5 +1,4 @@
1
1
  # SPDX-License-Identifier: MPL-2.0
2
- # -*- coding: utf-8 -*-
3
2
 
4
3
  from cryptoparser.common.field import (
5
4
  FieldValueComponentDateTime,
@@ -1,5 +1,4 @@
1
1
  # SPDX-License-Identifier: MPL-2.0
2
- # -*- coding: utf-8 -*-
3
2
 
4
3
  import enum
5
4
 
@@ -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: typing.List[DataAttributeBase] = attr.ib(
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: typing.List[Ikev1PayloadTransform] = attr.ib(validator=attr.validators.deep_iterable(
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=bytes(), converter=bytes, validator=attr.validators.instance_of(bytes))
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: typing.List[Ikev1Situation] = attr.ib(validator=attr.validators.deep_iterable(
412
+ situation: list[Ikev1Situation] = attr.ib(validator=attr.validators.deep_iterable(
413
413
  member_validator=attr.validators.instance_of(Ikev1Situation),
414
414
  ))
415
- proposals: typing.List[Ikev1PayloadProposal] = attr.ib(validator=attr.validators.deep_iterable(
415
+ proposals: list[Ikev1PayloadProposal] = attr.ib(validator=attr.validators.deep_iterable(
416
416
  member_validator=attr.validators.instance_of(Ikev1PayloadProposal),
417
417
  ))
418
418