regent-httpsig 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
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.
- regent_httpsig/__init__.py +1 -1
- regent_httpsig/verify.py +26 -1
- {regent_httpsig-0.1.0.dist-info → regent_httpsig-0.1.1.dist-info}/METADATA +9 -1
- {regent_httpsig-0.1.0.dist-info → regent_httpsig-0.1.1.dist-info}/RECORD +7 -7
- {regent_httpsig-0.1.0.dist-info → regent_httpsig-0.1.1.dist-info}/WHEEL +0 -0
- {regent_httpsig-0.1.0.dist-info → regent_httpsig-0.1.1.dist-info}/entry_points.txt +0 -0
- {regent_httpsig-0.1.0.dist-info → regent_httpsig-0.1.1.dist-info}/licenses/LICENSE +0 -0
regent_httpsig/__init__.py
CHANGED
|
@@ -11,7 +11,7 @@ from regent_httpsig.sfv import parse_signature_agent
|
|
|
11
11
|
from regent_httpsig.sign import DIRECTORY_MEDIA_TYPE, EgressSigner, generate_seed
|
|
12
12
|
from regent_httpsig.verify import WBA_TAG, HttpsigVerifier, VerifiedSignature
|
|
13
13
|
|
|
14
|
-
__version__ = "0.1.
|
|
14
|
+
__version__ = "0.1.1"
|
|
15
15
|
|
|
16
16
|
__all__ = [
|
|
17
17
|
"DIRECTORY_MEDIA_TYPE",
|
regent_httpsig/verify.py
CHANGED
|
@@ -84,6 +84,31 @@ class VerifiedSignature:
|
|
|
84
84
|
return out
|
|
85
85
|
|
|
86
86
|
|
|
87
|
+
class _KeyidOptionalParams(dict): # type: ignore[type-arg]
|
|
88
|
+
"""RFC 9421 makes ``keyid`` OPTIONAL, but the upstream verifier reads
|
|
89
|
+
``params["keyid"]`` unconditionally. On the AAuth path the key comes from
|
|
90
|
+
the token's ``cnf.jwk``, so conforming signers (e.g. aauth-signing) omit
|
|
91
|
+
keyid entirely. Returning None for a missing keyid routes resolution to our
|
|
92
|
+
StaticKeyResolver default WITHOUT adding the key to the params — iteration
|
|
93
|
+
is unchanged, so the reconstructed signature base stays byte-identical."""
|
|
94
|
+
|
|
95
|
+
def __getitem__(self, key: str) -> Any:
|
|
96
|
+
if key == "keyid" and key not in self:
|
|
97
|
+
return None
|
|
98
|
+
return super().__getitem__(key)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class _KeyidOptionalVerifier(HTTPMessageVerifier):
|
|
102
|
+
def _verify_one(self, *, label: Any, sig_input: Any, signature: Any,
|
|
103
|
+
message: Any, max_age: Any) -> Any:
|
|
104
|
+
if "keyid" not in sig_input.params:
|
|
105
|
+
sig_input.params = _KeyidOptionalParams(sig_input.params)
|
|
106
|
+
return super()._verify_one( # type: ignore[no-untyped-call]
|
|
107
|
+
label=label, sig_input=sig_input, signature=signature,
|
|
108
|
+
message=message, max_age=max_age,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
87
112
|
def _keys_from_jwks(doc: dict[str, Any]) -> dict[str, Ed25519PublicKey]:
|
|
88
113
|
keys: dict[str, Ed25519PublicKey] = {}
|
|
89
114
|
for jwk in list(doc.get("keys") or [])[:10]:
|
|
@@ -311,7 +336,7 @@ class HttpsigVerifier:
|
|
|
311
336
|
pop_key = load_ed25519_jwk(cnf_jwk)
|
|
312
337
|
except ValueError:
|
|
313
338
|
return None
|
|
314
|
-
verifier =
|
|
339
|
+
verifier = _KeyidOptionalVerifier(
|
|
315
340
|
signature_algorithm=ED25519,
|
|
316
341
|
key_resolver=StaticKeyResolver({}, default=pop_key),
|
|
317
342
|
component_resolver_class=DictKeyComponentResolver,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: regent-httpsig
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Verify and sign AI agent HTTP traffic in Python — RFC 9421 HTTP Message Signatures: Web Bot Auth (what OpenAI ships) and AAuth.
|
|
5
5
|
Project-URL: Homepage, https://github.com/regent-protocol/regent-httpsig
|
|
6
6
|
Project-URL: Repository, https://github.com/regent-protocol/regent-httpsig
|
|
@@ -101,6 +101,7 @@ and every Web Bot Auth verifier on the internet can now identify your agent.
|
|
|
101
101
|
| Web Bot Auth A.2.3 — legacy sf-string form (**what OpenAI ships in production**) | ✅ in CI |
|
|
102
102
|
| Sign → verify roundtrip (fresh keys, full pipeline) | ✅ in CI |
|
|
103
103
|
| AAuth identity-mode roundtrip (`aa-agent+jwt` + `cnf.jwk` proof of possession) | ✅ in CI |
|
|
104
|
+
| Signed by [`aauth-signing`](https://github.com/christian-posta/aauth-python-library) (jwt scheme, keyid-less) → verified | ✅² |
|
|
104
105
|
| Tampered request / expired signature / wrong directory key rejected | ✅ in CI |
|
|
105
106
|
|
|
106
107
|
¹ The signature bytes printed in the draft's own A.2.2 example do **not** verify over the
|
|
@@ -108,6 +109,13 @@ draft's own signature base (the legacy A.2.3 vector and RFC 9421 B.2.6 both do,
|
|
|
108
109
|
is in the example, not the canonicalization). Ed25519 is deterministic, so our test pins the
|
|
109
110
|
vector re-signed with the same RFC test key over the same byte-exact base — reported upstream.
|
|
110
111
|
|
|
112
|
+
² Cross-library interop with `aauth-signing`'s jwt scheme: token layer, `cnf.jwk` proof of
|
|
113
|
+
possession and canonicalization all verify. Its signers correctly omit the optional `keyid`
|
|
114
|
+
parameter — which exposed an unconditional `keyid` read in the underlying RFC 9421 library
|
|
115
|
+
that we now handle. One deviation reported upstream to `aauth-signing`: it emits the
|
|
116
|
+
`Signature` byte sequence as base64url, while RFC 8941 requires standard base64. The
|
|
117
|
+
keyid-less shape is pinned in CI.
|
|
118
|
+
|
|
111
119
|
## Both dialects, one verifier
|
|
112
120
|
|
|
113
121
|
- **Web Bot Auth** (`draft-meunier-web-bot-auth-architecture`): key discovery via
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
regent_httpsig/__init__.py,sha256=
|
|
1
|
+
regent_httpsig/__init__.py,sha256=xtujR5LyjhCFZ9uDuSZJoHTmM9PQglcCr5_AmiSTHNs,987
|
|
2
2
|
regent_httpsig/cli.py,sha256=WUSLQ2WuEX4E85L2C2EgoUfu5cWpj6MRSG1UVNHpzcw,2005
|
|
3
3
|
regent_httpsig/config.py,sha256=xkILlWugaD8Nn4huAgL6RP-C916KxCYRn0YpqCkMOGc,1422
|
|
4
4
|
regent_httpsig/fastapi.py,sha256=YmfrKdeMft2vpuiRlivIEHYC4BIs3ioR7T3t1ZEzcJ4,3707
|
|
@@ -6,9 +6,9 @@ regent_httpsig/jwk.py,sha256=h4vgnIgpnyKeWdWpm7g_hEyXZOPVREWn-bD4JN07tT0,1637
|
|
|
6
6
|
regent_httpsig/netguard.py,sha256=Sqg08mdC94RWvnQLJaH4weZW0nN2VlTJF5wVF8VYGHY,2121
|
|
7
7
|
regent_httpsig/sfv.py,sha256=kcQsBLw9h4h_6D3z2rv0-3_gLZQYC47B9VZi-oS_Vgk,4975
|
|
8
8
|
regent_httpsig/sign.py,sha256=B5ChxFxuuKL0i10bGrgFImzyh8GMjWIqNDECXehBWTA,4397
|
|
9
|
-
regent_httpsig/verify.py,sha256=
|
|
10
|
-
regent_httpsig-0.1.
|
|
11
|
-
regent_httpsig-0.1.
|
|
12
|
-
regent_httpsig-0.1.
|
|
13
|
-
regent_httpsig-0.1.
|
|
14
|
-
regent_httpsig-0.1.
|
|
9
|
+
regent_httpsig/verify.py,sha256=lGmGqlUKXtMlEDwoAanUZcz98XpPnY6rDe7CfuMXIiQ,15434
|
|
10
|
+
regent_httpsig-0.1.1.dist-info/METADATA,sha256=BePwZKhmLOt-Obf4Y3H-I1VWvXUM4juOiOI5w6tvki4,8488
|
|
11
|
+
regent_httpsig-0.1.1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
12
|
+
regent_httpsig-0.1.1.dist-info/entry_points.txt,sha256=SgZdmc27V14IAmwOjbBoCYLsbrALaqdTUHNHLbil2dU,59
|
|
13
|
+
regent_httpsig-0.1.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
14
|
+
regent_httpsig-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|