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.
@@ -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.0"
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 = HTTPMessageVerifier(
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.0
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=UZ-RmE0KLmqjD7JV7LnSOnPTc5FPO-5OtQzvsYq9PAs,987
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=YVcYWqxUBmqSdWrW8nBCSceT7YApAUjO5J-FIMKBRVM,14256
10
- regent_httpsig-0.1.0.dist-info/METADATA,sha256=4v_RgOudkaT3ui9921kZhM8R5fGfJbLl5e3e1pDBTh0,7871
11
- regent_httpsig-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
12
- regent_httpsig-0.1.0.dist-info/entry_points.txt,sha256=SgZdmc27V14IAmwOjbBoCYLsbrALaqdTUHNHLbil2dU,59
13
- regent_httpsig-0.1.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
14
- regent_httpsig-0.1.0.dist-info/RECORD,,
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,,