http-message-signatures 0.5.0__tar.gz → 0.6.1__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 (41) hide show
  1. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/.github/workflows/ci.yml +9 -6
  2. http_message_signatures-0.6.1/.github/workflows/release.yml +21 -0
  3. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/Changes.rst +11 -0
  4. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/LICENSE +0 -24
  5. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/Makefile +1 -1
  6. http_message_signatures-0.6.1/NOTICE +10 -0
  7. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/PKG-INFO +24 -17
  8. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/README.rst +6 -3
  9. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/common.mk +1 -7
  10. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/_algorithms.py +2 -2
  11. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/signatures.py +5 -2
  12. http_message_signatures-0.6.1/pyproject.toml +54 -0
  13. http_message_signatures-0.6.1/setup.cfg +3 -0
  14. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test.py +39 -4
  15. http-message-signatures-0.5.0/http_message_signatures/version.py +0 -16
  16. http-message-signatures-0.5.0/http_message_signatures.egg-info/PKG-INFO +0 -127
  17. http-message-signatures-0.5.0/http_message_signatures.egg-info/SOURCES.txt +0 -36
  18. http-message-signatures-0.5.0/http_message_signatures.egg-info/dependency_links.txt +0 -1
  19. http-message-signatures-0.5.0/http_message_signatures.egg-info/requires.txt +0 -11
  20. http-message-signatures-0.5.0/http_message_signatures.egg-info/top_level.txt +0 -1
  21. http-message-signatures-0.5.0/pyproject.toml +0 -7
  22. http-message-signatures-0.5.0/setup.cfg +0 -8
  23. http-message-signatures-0.5.0/setup.py +0 -49
  24. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/.github/FUNDING.yml +0 -0
  25. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/.gitignore +0 -0
  26. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/docs/conf.py +0 -0
  27. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/docs/index.rst +0 -0
  28. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/__init__.py +0 -0
  29. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/algorithms.py +0 -0
  30. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/exceptions.py +0 -0
  31. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/py.typed +0 -0
  32. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/resolvers.py +0 -0
  33. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/http_message_signatures/structures.py +0 -0
  34. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-ecc-p256.key +0 -0
  35. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-ecc-p256.pem +0 -0
  36. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-ed25519.key +0 -0
  37. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-ed25519.pem +0 -0
  38. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-rsa-pss.key +0 -0
  39. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-rsa-pss.pem +0 -0
  40. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-rsa.key +0 -0
  41. {http-message-signatures-0.5.0 → http_message_signatures-0.6.1}/test/test-key-rsa.pem +0 -0
@@ -10,7 +10,7 @@ jobs:
10
10
  fail-fast: false
11
11
  max-parallel: 8
12
12
  matrix:
13
- python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
13
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14
14
 
15
15
  steps:
16
16
  - uses: actions/checkout@v4
@@ -23,13 +23,16 @@ jobs:
23
23
  run: pip install .[tests]
24
24
  - name: Test
25
25
  run: make test
26
- black:
27
- runs-on: ubuntu-22.04
28
- steps:
29
- - uses: actions/checkout@v4
30
- - uses: psf/black@stable
31
26
  isort:
32
27
  runs-on: ubuntu-22.04
33
28
  steps:
34
29
  - uses: actions/checkout@v4
35
30
  - uses: isort/isort-action@v1.1.0
31
+ ruff:
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: astral-sh/ruff-action@v3
36
+ - uses: astral-sh/ruff-action@v3
37
+ with:
38
+ args: "format --check"
@@ -0,0 +1,21 @@
1
+ name: Publish release to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v[0-9]+.[0-9]+.[0-9]+'
7
+
8
+ jobs:
9
+ pypi-publish:
10
+ name: Build and upload release to PyPI
11
+ runs-on: ubuntu-latest
12
+ environment: release
13
+ permissions:
14
+ id-token: write
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ - run: pip install build
19
+ - run: python -m build
20
+ - name: Publish package distributions to PyPI
21
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,3 +1,14 @@
1
+ Changes for v0.6.1 (2025-05-29)
2
+ ===============================
3
+
4
+ - Switch to trusted publishing
5
+
6
+ Changes for v0.6.0 (2025-05-29)
7
+ ===============================
8
+
9
+ - [http-message-signatures-add] Add support for ‘tag’ signature
10
+ parameter (#17)
11
+
1
12
  Changes for v0.5.0 (2024-02-21)
2
13
  ===============================
3
14
 
@@ -165,27 +165,3 @@ incurred by, or claims asserted against, such Contributor by reason of your
165
165
  accepting any such warranty or additional liability.
166
166
 
167
167
  END OF TERMS AND CONDITIONS
168
-
169
- APPENDIX: How to apply the Apache License to your work
170
-
171
- To apply the Apache License to your work, attach the following boilerplate
172
- notice, with the fields enclosed by brackets "[]" replaced with your own
173
- identifying information. (Don't include the brackets!) The text should be
174
- enclosed in the appropriate comment syntax for the file format. We also
175
- recommend that a file or class name and description of purpose be included on
176
- the same "printed page" as the copyright notice for easier identification within
177
- third-party archives.
178
-
179
- Copyright [yyyy] [name of copyright owner]
180
-
181
- Licensed under the Apache License, Version 2.0 (the "License");
182
- you may not use this file except in compliance with the License.
183
- You may obtain a copy of the License at
184
-
185
- http://www.apache.org/licenses/LICENSE-2.0
186
-
187
- Unless required by applicable law or agreed to in writing, software
188
- distributed under the License is distributed on an "AS IS" BASIS,
189
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
- See the License for the specific language governing permissions and
191
- limitations under the License.
@@ -1,7 +1,7 @@
1
1
  SHELL=/bin/bash
2
2
 
3
3
  lint:
4
- ruff http_message_signatures
4
+ ruff check http_message_signatures
5
5
  mypy --check-untyped-defs http_message_signatures
6
6
 
7
7
  test: lint
@@ -0,0 +1,10 @@
1
+ http-message-signatures is a free open source implementation of the
2
+ IETF HTTP Message Signatures standard, RFC 9421. This project is
3
+ staffed by volunteers. If you are using http-message-signatures in a
4
+ for-profit project, please contribute to its development and
5
+ maintenance using the "Sponsor" button on the GitHub project page,
6
+ https://github.com/pyauth/http-message-signatures. If you are looking
7
+ for support with commercial applications based on
8
+ http-message-signatures, please donate and contact its developers
9
+ using the issue tracker on the http-message-signatures project page or
10
+ the contact information listed in README.rst.
@@ -1,13 +1,15 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: http-message-signatures
3
- Version: 0.5.0
3
+ Version: 0.6.1
4
4
  Summary: An implementation of the IETF HTTP Message Signatures draft standard
5
- Home-page: https://github.com/pyauth/http-message-signatures
5
+ Project-URL: Homepage, https://github.com/pyauth/http-message-signatures
6
6
  Author: Andrey Kislyuk
7
7
  Author-email: kislyuk@gmail.com
8
+ Maintainer: Andrey Kislyuk
9
+ Maintainer-email: kislyuk@gmail.com
8
10
  License: Apache Software License
9
- Platform: MacOS X
10
- Platform: Posix
11
+ License-File: LICENSE
12
+ License-File: NOTICE
11
13
  Classifier: Intended Audience :: Developers
12
14
  Classifier: License :: OSI Approved :: Apache Software License
13
15
  Classifier: Operating System :: MacOS :: MacOS X
@@ -18,24 +20,26 @@ Classifier: Programming Language :: Python :: 3.9
18
20
  Classifier: Programming Language :: Python :: 3.10
19
21
  Classifier: Programming Language :: Python :: 3.11
20
22
  Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
21
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
- License-File: LICENSE
23
- Requires-Dist: http-sfv>=0.9.3
25
+ Requires-Python: >=3.8
24
26
  Requires-Dist: cryptography>=36.0.2
27
+ Requires-Dist: http-sfv>=0.9.3
25
28
  Provides-Extra: tests
26
- Requires-Dist: flake8; extra == "tests"
27
- Requires-Dist: coverage; extra == "tests"
28
- Requires-Dist: build; extra == "tests"
29
- Requires-Dist: wheel; extra == "tests"
30
- Requires-Dist: mypy; extra == "tests"
31
- Requires-Dist: requests; extra == "tests"
32
- Requires-Dist: ruff; extra == "tests"
29
+ Requires-Dist: build; extra == 'tests'
30
+ Requires-Dist: coverage; extra == 'tests'
31
+ Requires-Dist: flake8; extra == 'tests'
32
+ Requires-Dist: mypy; extra == 'tests'
33
+ Requires-Dist: requests; extra == 'tests'
34
+ Requires-Dist: ruff; extra == 'tests'
35
+ Requires-Dist: wheel; extra == 'tests'
36
+ Description-Content-Type: text/x-rst
33
37
 
34
38
  http-message-signatures: An implementation of RFC 9421, the IETF HTTP Message Signatures standard
35
39
  =================================================================================================
36
40
 
37
41
  *http-message-signatures* is an implementation of the IETF
38
- `RFC 9421 HTTP Message Signatures <https://datatracker.ietf.org/doc/rfc9421/>`_ draft standard in
42
+ `RFC 9421 HTTP Message Signatures <https://datatracker.ietf.org/doc/rfc9421/>`_ standard in
39
43
  Python.
40
44
 
41
45
  Installation
@@ -107,7 +111,7 @@ digest etc.)
107
111
 
108
112
  Authors
109
113
  -------
110
- * Andrey Kislyuk
114
+ * `Andrey Kislyuk <https://kislyuk.com>`
111
115
 
112
116
  Links
113
117
  -----
@@ -124,4 +128,7 @@ Please report bugs, issues, feature requests, etc. on `GitHub <https://github.co
124
128
 
125
129
  License
126
130
  -------
127
- Licensed under the terms of the `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
131
+ Copyright 2017-2024, Andrey Kislyuk and http-message-signatures contributors. Licensed under the terms of the
132
+ `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_. Distribution of attribution information,
133
+ LICENSE and NOTICE files with source copies of this package and derivative works is **REQUIRED** as specified by the
134
+ Apache License.
@@ -2,7 +2,7 @@ http-message-signatures: An implementation of RFC 9421, the IETF HTTP Message Si
2
2
  =================================================================================================
3
3
 
4
4
  *http-message-signatures* is an implementation of the IETF
5
- `RFC 9421 HTTP Message Signatures <https://datatracker.ietf.org/doc/rfc9421/>`_ draft standard in
5
+ `RFC 9421 HTTP Message Signatures <https://datatracker.ietf.org/doc/rfc9421/>`_ standard in
6
6
  Python.
7
7
 
8
8
  Installation
@@ -74,7 +74,7 @@ digest etc.)
74
74
 
75
75
  Authors
76
76
  -------
77
- * Andrey Kislyuk
77
+ * `Andrey Kislyuk <https://kislyuk.com>`
78
78
 
79
79
  Links
80
80
  -----
@@ -91,4 +91,7 @@ Please report bugs, issues, feature requests, etc. on `GitHub <https://github.co
91
91
 
92
92
  License
93
93
  -------
94
- Licensed under the terms of the `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
94
+ Copyright 2017-2024, Andrey Kislyuk and http-message-signatures contributors. Licensed under the terms of the
95
+ `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_. Distribution of attribution information,
96
+ LICENSE and NOTICE files with source copies of this package and derivative works is **REQUIRED** as specified by the
97
+ Apache License.
@@ -18,9 +18,8 @@ release:
18
18
  @if ! type -P pandoc; then echo "Please install pandoc"; exit 1; fi
19
19
  @if ! type -P sponge; then echo "Please install moreutils"; exit 1; fi
20
20
  @if ! type -P gh; then echo "Please install gh"; exit 1; fi
21
- @if ! type -P twine; then echo "Please install twine"; exit 1; fi
22
21
  git pull
23
- git clean -x --force $$(python setup.py --name)
22
+ git clean -x --force $$(ls */__init__.py | xargs dirname)
24
23
  TAG_MSG=$$(mktemp); \
25
24
  echo "# Changes for ${TAG} ($$(date +%Y-%m-%d))" > $$TAG_MSG; \
26
25
  git log --pretty=format:%s $$(git describe --abbrev=0)..HEAD >> $$TAG_MSG; \
@@ -32,10 +31,5 @@ release:
32
31
  git push --follow-tags
33
32
  $(MAKE) install
34
33
  gh release create ${TAG} dist/*.whl --notes="$$(git tag --list ${TAG} -n99 | perl -pe 's/^\S+\s*// if $$. == 1' | sed 's/^\s\s\s\s//')"
35
- $(MAKE) release-pypi
36
-
37
- release-pypi:
38
- python -m build
39
- twine upload dist/*.tar.gz dist/*.whl --verbose
40
34
 
41
35
  .PHONY: release
@@ -91,9 +91,9 @@ class ECDSA_P256_SHA256(HTTPSignatureAlgorithm, PEMKeyLoader):
91
91
  raise HTTPMessageSignaturesException("Unexpected public key type")
92
92
  if self.private_key and not isinstance(self.private_key, ec.EllipticCurvePrivateKey):
93
93
  raise HTTPMessageSignaturesException("Unexpected private key type")
94
- if self.public_key and type(self.public_key.curve) != ec.SECP256R1:
94
+ if self.public_key and not isinstance(self.public_key.curve, ec.SECP256R1):
95
95
  raise HTTPMessageSignaturesException("Unexpected elliptic curve type in public key")
96
- if self.private_key and type(self.private_key.curve) != ec.SECP256R1:
96
+ if self.private_key and not isinstance(self.private_key.curve, ec.SECP256R1):
97
97
  raise HTTPMessageSignaturesException("Unexpected elliptic curve type in private key")
98
98
  self.signature_algorithm = ec.ECDSA(hashes.SHA256())
99
99
 
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
16
  class HTTPSignatureHandler:
17
- signature_metadata_parameters = {"alg", "created", "expires", "keyid", "nonce"}
17
+ signature_metadata_parameters = {"alg", "created", "expires", "keyid", "nonce", "tag"}
18
18
 
19
19
  def __init__(
20
20
  self,
@@ -46,7 +46,7 @@ class HTTPSignatureHandler:
46
46
  raise HTTPMessageSignaturesException(f'Component ID "{component_key}" contains newline character')
47
47
  if component_key in sig_elements:
48
48
  raise HTTPMessageSignaturesException(
49
- f'Component ID "{component_key}" appeared multiple times in ' "signature input"
49
+ f'Component ID "{component_key}" appeared multiple times in signature input'
50
50
  )
51
51
  sig_elements[component_key] = component_value
52
52
  sig_params_node = http_sfv.InnerList(covered_component_ids)
@@ -79,6 +79,7 @@ class HTTPMessageSigner(HTTPSignatureHandler):
79
79
  expires: Optional[datetime.datetime] = None,
80
80
  nonce: Optional[str] = None,
81
81
  label: Optional[str] = None,
82
+ tag: Optional[str] = None,
82
83
  include_alg: bool = True,
83
84
  covered_component_ids: Sequence[str] = ("@method", "@authority", "@target-uri"),
84
85
  ):
@@ -93,6 +94,8 @@ class HTTPMessageSigner(HTTPSignatureHandler):
93
94
  signature_params["expires"] = int(expires.timestamp())
94
95
  if nonce:
95
96
  signature_params["nonce"] = nonce
97
+ if tag:
98
+ signature_params["tag"] = tag
96
99
  if include_alg:
97
100
  signature_params["alg"] = self.signature_algorithm.algorithm_id
98
101
  covered_component_nodes = self._parse_covered_component_ids(covered_component_ids)
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "http-message-signatures"
3
+ description = "An implementation of the IETF HTTP Message Signatures draft standard"
4
+ readme = "README.rst"
5
+ requires-python = ">=3.8"
6
+ license = {text = "Apache Software License"}
7
+ authors = [{ name = "Andrey Kislyuk"}, {email = "kislyuk@gmail.com" }]
8
+ maintainers = [{ name = "Andrey Kislyuk"}, {email = "kislyuk@gmail.com" }]
9
+ dynamic = ["version"]
10
+ classifiers = [
11
+ "Intended Audience :: Developers",
12
+ "License :: OSI Approved :: Apache Software License",
13
+ "Operating System :: MacOS :: MacOS X",
14
+ "Operating System :: POSIX",
15
+ "Programming Language :: Python",
16
+ "Programming Language :: Python :: 3.8",
17
+ "Programming Language :: Python :: 3.9",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ ]
24
+ dependencies = [
25
+ "http-sfv >= 0.9.3",
26
+ "cryptography >= 36.0.2",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/pyauth/http-message-signatures"
31
+
32
+ [project.optional-dependencies]
33
+ tests = [
34
+ "flake8",
35
+ "coverage",
36
+ "build",
37
+ "wheel",
38
+ "mypy",
39
+ "requests",
40
+ "ruff",
41
+ ]
42
+
43
+ [build-system]
44
+ requires = ["hatchling", "hatch-vcs"]
45
+ build-backend = "hatchling.build"
46
+
47
+ [tool.hatch.version]
48
+ source = "vcs"
49
+
50
+ [tool.isort]
51
+ profile = "black"
52
+
53
+ [tool.ruff]
54
+ line-length = 120
@@ -0,0 +1,3 @@
1
+ [flake8]
2
+ max-line-length=120
3
+ ignore=E401
@@ -31,7 +31,7 @@ from http_message_signatures.algorithms import ( # noqa
31
31
  )
32
32
 
33
33
  test_shared_secret = base64.b64decode(
34
- "uzvJfB4u3N0Jy4T7NZ75MDVcr8zSTInedJtkgcu46YW4XByzNJjxBdtjUkdJPBtbmHhIDi6pcl8jsasj" "lTMtDQ=="
34
+ "uzvJfB4u3N0Jy4T7NZ75MDVcr8zSTInedJtkgcu46YW4XByzNJjxBdtjUkdJPBtbmHhIDi6pcl8jsasjlTMtDQ=="
35
35
  )
36
36
 
37
37
 
@@ -59,7 +59,7 @@ class TestHTTPMessageSignatures(unittest.TestCase):
59
59
  self.test_request = request.prepare()
60
60
  self.test_request.headers["Date"] = "Tue, 20 Apr 2021 02:07:55 GMT"
61
61
  self.test_request.headers["Content-Digest"] = (
62
- "sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+" "AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:"
62
+ "sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:"
63
63
  )
64
64
  self.test_response = requests.Response()
65
65
  self.test_response.request = self.test_request
@@ -68,7 +68,7 @@ class TestHTTPMessageSignatures(unittest.TestCase):
68
68
  "Date": "Tue, 20 Apr 2021 02:07:56 GMT",
69
69
  "Content-Type": "application/json",
70
70
  "Content-Digest": (
71
- "sha-512=:JlEy2bfUz7WrWIjc1qV6KVLpdr/7L5/L4h7Sxvh6sNHpDQWDCL+" "GauFQWcZBvVDhiyOnAQsxzZFYwi0wDH+1pw==:"
71
+ "sha-512=:JlEy2bfUz7WrWIjc1qV6KVLpdr/7L5/L4h7Sxvh6sNHpDQWDCL+GauFQWcZBvVDhiyOnAQsxzZFYwi0wDH+1pw==:"
72
72
  ),
73
73
  "Content-Length": "23",
74
74
  }
@@ -205,7 +205,7 @@ class TestHTTPMessageSignatures(unittest.TestCase):
205
205
  verifier = HTTPMessageVerifier(signature_algorithm=ECDSA_P256_SHA256, key_resolver=self.key_resolver)
206
206
  self.verify(verifier, self.test_response)
207
207
  self.test_response.headers["Signature"] = (
208
- "sig-b24=:0Ry6HsvzS5VmA6HlfBYS/fYYeNs7fYuA7s0tAdxfUlPGv0CSVuwrrzBOjc" "CFHTxVRJ01wjvSzM2BetJauj8dsw==:"
208
+ "sig-b24=:0Ry6HsvzS5VmA6HlfBYS/fYYeNs7fYuA7s0tAdxfUlPGv0CSVuwrrzBOjcCFHTxVRJ01wjvSzM2BetJauj8dsw==:"
209
209
  )
210
210
  self.verify(verifier, self.test_response)
211
211
 
@@ -262,6 +262,41 @@ class TestHTTPMessageSignatures(unittest.TestCase):
262
262
  with self.assertRaises(InvalidSignature):
263
263
  verifier.verify(self.test_request, max_age=self.max_age)
264
264
 
265
+ def test_http_message_signatures_B27(self):
266
+ signer = HTTPMessageSigner(signature_algorithm=ED25519, key_resolver=self.key_resolver)
267
+ signer.sign(
268
+ self.test_request,
269
+ key_id="test-key-ed25519",
270
+ covered_component_ids=("date", "@method", "@path", "@authority", "content-type", "content-length"),
271
+ created=datetime.fromtimestamp(1618884473),
272
+ label="sig-b27",
273
+ tag="tag-b27",
274
+ include_alg=False,
275
+ )
276
+ self.assertEqual(
277
+ self.test_request.headers["Signature-Input"],
278
+ (
279
+ 'sig-b27=("date" "@method" "@path" "@authority" "content-type" "content-length");'
280
+ 'created=1618884473;keyid="test-key-ed25519";tag="tag-b27"'
281
+ ),
282
+ )
283
+ signature = "sig-b27=:pDPhW4vxi28JZfogrM4NLeYhZKW+TYDko8KtzCFoTOFeGCCSivD0iVcIuT9gqM6AtGfgzqQU/GaoLqh8sC6bCg==:"
284
+ self.assertEqual(self.test_request.headers["Signature"], signature)
285
+ verifier = HTTPMessageVerifier(signature_algorithm=ED25519, key_resolver=self.key_resolver)
286
+ result = self.verify(verifier, self.test_request)[0]
287
+
288
+ self.assertEqual(result.parameters["keyid"], "test-key-ed25519")
289
+ self.assertEqual(result.parameters["tag"], "tag-b27")
290
+ self.assertIn("created", result.parameters)
291
+ self.assertEqual(result.label, "sig-b27")
292
+
293
+ self.test_request.headers["Signature"] = "sig-b26=:pxcQw6G3AjtMBQjwo8XzkZf/bws5LelbaMk5rGIGtE8=:"
294
+ with self.assertRaises(InvalidSignature):
295
+ verifier.verify(self.test_request, max_age=self.max_age)
296
+ self.test_request.headers["Signature"] = signature[::-1]
297
+ with self.assertRaises(InvalidSignature):
298
+ verifier.verify(self.test_request, max_age=self.max_age)
299
+
265
300
  def test_query_parameters(self):
266
301
  signer = HTTPMessageSigner(signature_algorithm=HMAC_SHA256, key_resolver=self.key_resolver)
267
302
  signer.sign(
@@ -1,16 +0,0 @@
1
- # file generated by setuptools_scm
2
- # don't change, don't track in version control
3
- TYPE_CHECKING = False
4
- if TYPE_CHECKING:
5
- from typing import Tuple, Union
6
- VERSION_TUPLE = Tuple[Union[int, str], ...]
7
- else:
8
- VERSION_TUPLE = object
9
-
10
- version: str
11
- __version__: str
12
- __version_tuple__: VERSION_TUPLE
13
- version_tuple: VERSION_TUPLE
14
-
15
- __version__ = version = '0.5.0'
16
- __version_tuple__ = version_tuple = (0, 5, 0)
@@ -1,127 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: http-message-signatures
3
- Version: 0.5.0
4
- Summary: An implementation of the IETF HTTP Message Signatures draft standard
5
- Home-page: https://github.com/pyauth/http-message-signatures
6
- Author: Andrey Kislyuk
7
- Author-email: kislyuk@gmail.com
8
- License: Apache Software License
9
- Platform: MacOS X
10
- Platform: Posix
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: Apache Software License
13
- Classifier: Operating System :: MacOS :: MacOS X
14
- Classifier: Operating System :: POSIX
15
- Classifier: Programming Language :: Python
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
- License-File: LICENSE
23
- Requires-Dist: http-sfv>=0.9.3
24
- Requires-Dist: cryptography>=36.0.2
25
- Provides-Extra: tests
26
- Requires-Dist: flake8; extra == "tests"
27
- Requires-Dist: coverage; extra == "tests"
28
- Requires-Dist: build; extra == "tests"
29
- Requires-Dist: wheel; extra == "tests"
30
- Requires-Dist: mypy; extra == "tests"
31
- Requires-Dist: requests; extra == "tests"
32
- Requires-Dist: ruff; extra == "tests"
33
-
34
- http-message-signatures: An implementation of RFC 9421, the IETF HTTP Message Signatures standard
35
- =================================================================================================
36
-
37
- *http-message-signatures* is an implementation of the IETF
38
- `RFC 9421 HTTP Message Signatures <https://datatracker.ietf.org/doc/rfc9421/>`_ draft standard in
39
- Python.
40
-
41
- Installation
42
- ------------
43
- ::
44
-
45
- pip3 install http-message-signatures
46
-
47
- Synopsis
48
- --------
49
-
50
- .. code-block:: python
51
-
52
- from http_message_signatures import HTTPMessageSigner, HTTPMessageVerifier, HTTPSignatureKeyResolver, algorithms
53
- import requests, base64, hashlib, http_sfv
54
-
55
- class MyHTTPSignatureKeyResolver(HTTPSignatureKeyResolver):
56
- keys = {"my-key": b"top-secret-key"}
57
-
58
- def resolve_public_key(self, key_id: str):
59
- return self.keys[key_id]
60
-
61
- def resolve_private_key(self, key_id: str):
62
- return self.keys[key_id]
63
-
64
- request = requests.Request('POST', 'https://example.com/foo?param=Value&Pet=dog', json={"hello": "world"})
65
- request = request.prepare()
66
- request.headers["Content-Digest"] = str(http_sfv.Dictionary({"sha-256": hashlib.sha256(request.body).digest()}))
67
-
68
- signer = HTTPMessageSigner(signature_algorithm=algorithms.HMAC_SHA256, key_resolver=MyHTTPSignatureKeyResolver())
69
- signer.sign(request, key_id="my-key", covered_component_ids=("@method", "@authority", "@target-uri", "content-digest"))
70
-
71
- verifier = HTTPMessageVerifier(signature_algorithm=algorithms.HMAC_SHA256, key_resolver=MyHTTPSignatureKeyResolver())
72
- verifier.verify(request)
73
-
74
- Note that verifying the body content-digest is outside the scope of this package's functionality, so it remains the
75
- caller's responsibility. The `requests-http-signature <https://github.com/pyauth/requests-http-signature>`_ library
76
- builds upon this package to provide integrated signing and validation of the request body.
77
-
78
- .. admonition:: See what is signed
79
-
80
- It is important to understand and follow the best practice rule of "See what is signed" when verifying HTTP message
81
- signatures. The gist of this rule is: if your application neglects to verify that the information it trusts is
82
- what was actually signed, the attacker can supply a valid signature but point you to malicious data that wasn't signed
83
- by that signature. Failure to follow this rule can lead to vulnerability against signature wrapping and substitution
84
- attacks.
85
-
86
- In http-message-signatures, you can ensure that the information signed is what you expect to be signed by only trusting the
87
- data returned by the ``verify()`` method::
88
-
89
- verify_results = verifier.verify(request)
90
-
91
- This returns a list of ``VerifyResult`` s, which are ``namedtuple`` s with the following attributes:
92
-
93
- * label (str): The label for the signature
94
- * algorithm: (same as signature_algorithm above)
95
- * covered_components: A mapping of component names to their values, as covered by the signature
96
- * parameters: A mapping of signature parameters to their values, as covered by the signature
97
- * body: Always ``None`` (the `requests-http-signature <https://github.com/pyauth/requests-http-signature>`_ package
98
- implements returning the body upon successful digest validation).
99
-
100
- Given an HTTP request can potentially have multiple signatures the ``verify()`` method returns a list of ``VerifyResult`` s.
101
- However, the implementation currently supports just one signature, so the returned list currently contains just one element.
102
- If more signatures are found in the request then ``InvalidSignature`` is raised.
103
-
104
- Additionally, the ``verify()`` method raises ``HTTPMessageSignaturesException`` or an exception derived from this class in
105
- case an error occurs (unable to load PEM key, unsupported algorithm specified in signature input, signature doesn't match
106
- digest etc.)
107
-
108
- Authors
109
- -------
110
- * Andrey Kislyuk
111
-
112
- Links
113
- -----
114
- * `Project home page (GitHub) <https://github.com/pyauth/http-message-signatures>`_
115
- * `Documentation <https://FIXME>`_
116
- * `Package distribution (PyPI) <https://pypi.python.org/pypi/http-message-signatures>`_
117
- * `Change log <https://github.com/pyauth/http-message-signatures/blob/master/Changes.rst>`_
118
- * `IETF HTTP Message Signatures standard tracker <https://datatracker.ietf.org/doc/rfc9421/>`_
119
- * `OWASP Top Ten <https://owasp.org/www-project-top-ten/>`_
120
-
121
- Bugs
122
- ~~~~
123
- Please report bugs, issues, feature requests, etc. on `GitHub <https://github.com/pyauth/http-message-signatures/issues>`_.
124
-
125
- License
126
- -------
127
- Licensed under the terms of the `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
@@ -1,36 +0,0 @@
1
- .gitignore
2
- Changes.rst
3
- LICENSE
4
- Makefile
5
- README.rst
6
- common.mk
7
- pyproject.toml
8
- setup.cfg
9
- setup.py
10
- .github/FUNDING.yml
11
- .github/workflows/ci.yml
12
- docs/conf.py
13
- docs/index.rst
14
- http_message_signatures/__init__.py
15
- http_message_signatures/_algorithms.py
16
- http_message_signatures/algorithms.py
17
- http_message_signatures/exceptions.py
18
- http_message_signatures/py.typed
19
- http_message_signatures/resolvers.py
20
- http_message_signatures/signatures.py
21
- http_message_signatures/structures.py
22
- http_message_signatures/version.py
23
- http_message_signatures.egg-info/PKG-INFO
24
- http_message_signatures.egg-info/SOURCES.txt
25
- http_message_signatures.egg-info/dependency_links.txt
26
- http_message_signatures.egg-info/requires.txt
27
- http_message_signatures.egg-info/top_level.txt
28
- test/test-key-ecc-p256.key
29
- test/test-key-ecc-p256.pem
30
- test/test-key-ed25519.key
31
- test/test-key-ed25519.pem
32
- test/test-key-rsa-pss.key
33
- test/test-key-rsa-pss.pem
34
- test/test-key-rsa.key
35
- test/test-key-rsa.pem
36
- test/test.py
@@ -1,11 +0,0 @@
1
- http-sfv>=0.9.3
2
- cryptography>=36.0.2
3
-
4
- [tests]
5
- flake8
6
- coverage
7
- build
8
- wheel
9
- mypy
10
- requests
11
- ruff
@@ -1 +0,0 @@
1
- http_message_signatures
@@ -1,7 +0,0 @@
1
- [tool.black]
2
- line-length = 120
3
- exclude = ".*/version.py"
4
- [tool.isort]
5
- profile = "black"
6
- [tool.ruff]
7
- line-length=120
@@ -1,8 +0,0 @@
1
- [flake8]
2
- max-line-length = 120
3
- ignore = E401
4
-
5
- [egg_info]
6
- tag_build =
7
- tag_date = 0
8
-
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- from setuptools import find_packages, setup # type: ignore
4
-
5
- setup(
6
- name="http-message-signatures",
7
- url="https://github.com/pyauth/http-message-signatures",
8
- license="Apache Software License",
9
- author="Andrey Kislyuk",
10
- author_email="kislyuk@gmail.com",
11
- description="An implementation of the IETF HTTP Message Signatures draft standard",
12
- long_description=open("README.rst").read(),
13
- use_scm_version={
14
- "write_to": "http_message_signatures/version.py",
15
- },
16
- setup_requires=["setuptools_scm >= 3.4.3"],
17
- install_requires=["http-sfv >= 0.9.3", "cryptography >= 36.0.2"],
18
- extras_require={
19
- "tests": [
20
- "flake8",
21
- "coverage",
22
- "build",
23
- "wheel",
24
- "mypy",
25
- "requests",
26
- "ruff",
27
- ]
28
- },
29
- packages=find_packages(exclude=["test"]),
30
- include_package_data=True,
31
- package_data={
32
- "http_message_signatures": ["py.typed"],
33
- },
34
- platforms=["MacOS X", "Posix"],
35
- test_suite="test",
36
- classifiers=[
37
- "Intended Audience :: Developers",
38
- "License :: OSI Approved :: Apache Software License",
39
- "Operating System :: MacOS :: MacOS X",
40
- "Operating System :: POSIX",
41
- "Programming Language :: Python",
42
- "Programming Language :: Python :: 3.8",
43
- "Programming Language :: Python :: 3.9",
44
- "Programming Language :: Python :: 3.10",
45
- "Programming Language :: Python :: 3.11",
46
- "Programming Language :: Python :: 3.12",
47
- "Topic :: Software Development :: Libraries :: Python Modules",
48
- ],
49
- )