From af0db442f59b27a0e83bc63931950ce364f9a936 Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Mon, 15 Jun 2026 11:19:18 +0000 Subject: [PATCH] Produce fixed-sized x&y --- tests/infra/jwt_issuer.py | 8 ++-- .../custom_authorization.py | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/tests/infra/jwt_issuer.py b/tests/infra/jwt_issuer.py index 00611ff9be1..76f38ab7068 100644 --- a/tests/infra/jwt_issuer.py +++ b/tests/infra/jwt_issuer.py @@ -139,8 +139,8 @@ def get_jwt_keys(args, node): return body["keys"] -def to_b64(number: int): - as_bytes = number.to_bytes((number.bit_length() + 7) // 8, "big") +def to_b64(number: int, size=None): + as_bytes = number.to_bytes(size or (number.bit_length() + 7) // 8, "big") # JWK numeric fields use unpadded base64url (RFC 7518 section 6 referencing # RFC 4648 section 5). return base64.urlsafe_b64encode(as_bytes).rstrip(b"=").decode("ascii") @@ -222,8 +222,8 @@ def _create_jwks_with_raw_key(self, kid): e = to_b64(pubkey.public_numbers().e) return {"kty": "RSA", "kid": kid, "n": n, "e": e, "issuer": self.name[::]} elif self._alg == JwtAlg.ES256: - x = to_b64(pubkey.public_numbers().x) - y = to_b64(pubkey.public_numbers().y) + x = to_b64(pubkey.public_numbers().x, 32) + y = to_b64(pubkey.public_numbers().y, 32) return { "kty": "EC", "kid": kid, diff --git a/tests/js-custom-authorization/custom_authorization.py b/tests/js-custom-authorization/custom_authorization.py index b259f198919..8edf67c1361 100644 --- a/tests/js-custom-authorization/custom_authorization.py +++ b/tests/js-custom-authorization/custom_authorization.py @@ -109,6 +109,42 @@ def parse_error_message(r): return r.body.json()["error"]["details"][0]["message"] +class FixedPublicKey: + def __init__(self, x, y): + self.x = x + self.y = y + + def public_numbers(self): + return self + + +class FixedPublicKeyIssuer(JwtIssuer): + @property + def public_key(self): + return self._public_key + + +def assert_es256_raw_jwk_coordinates_are_fixed_width(): + x_bytes = b"\x00" + bytes(range(1, 32)) + y_bytes = b"\x00" + bytes(range(32, 63)) + + # Use fixed public numbers rather than generated keys. + issuer = object.__new__(FixedPublicKeyIssuer) + issuer.name = "https://noautorefresh.example/issuer" + issuer._auth_type = JwtAuthType.KEY + issuer._alg = JwtAlg.ES256 + issuer._public_key = FixedPublicKey( + int.from_bytes(x_bytes, "big"), int.from_bytes(y_bytes, "big") + ) + jwk = issuer.create_jwks("my_key_id")["keys"][0] + + assert jwk["crv"] == "P-256" + + # Expected unpadded base64url, preserving the leading zero byte. + assert jwk["x"] == "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8" + assert jwk["y"] == "ACAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4" + + def try_auth(primary, issuer, kid, iss, tid): with primary.client("user0") as c: LOG.info(f"Creating JWT with kid={kid} iss={iss} tenant={tid}") @@ -444,6 +480,7 @@ def test_jwt_auth(network, args): @reqs.description("JWT authentication as by OpenID spec with raw public key") def test_jwt_auth_raw_key(network, args): + assert_es256_raw_jwk_coordinates_are_fixed_width() primary, _ = network.find_nodes() for alg in [JwtAlg.RS256, JwtAlg.ES256]: