-
Notifications
You must be signed in to change notification settings - Fork 1.7k
chore(generator): add post-quantum cryptography (PQC) integration tests #17586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
bdad053
6c043e6
449f2e6
f476283
2d0fe09
30c6ecc
4e3be17
03ac316
ee8b1c8
2620f09
63f33f2
7b52775
7283c3b
a3d4c58
bd15409
fbc8830
ce88e4a
c19087d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import grpc | ||
| from packaging.version import Version | ||
| import pytest | ||
| from google import showcase | ||
|
|
||
|
|
||
| @pytest.fixture(autouse=True) | ||
| def require_tls(use_tls): | ||
| if not use_tls: | ||
| pytest.skip("PQC integration test requires standard TLS (--tls flag) to be enabled.") | ||
|
|
||
|
|
||
| def _verify_pqc_metadata(interceptor, transport_name): | ||
| """Extracts and verifies negotiated PQC group and supported groups from interceptor metadata.""" | ||
| response_metadata = getattr(interceptor, "response_metadata", []) or [] | ||
| headers = {key.lower(): value for key, value in response_metadata} | ||
| negotiated_group = headers.get("x-showcase-tls-group") | ||
| supported_groups = headers.get("x-showcase-tls-client-supported-groups") | ||
|
|
||
| assert negotiated_group is not None, "Failed: Showcase server did not return negotiated TLS group header." | ||
| assert supported_groups is not None, "Failed: Showcase server did not return client advertised supported groups." | ||
|
|
||
| # Enforce PQC compliance (X25519MLKEM768) | ||
| assert ( | ||
| "MLKEM" in negotiated_group | ||
| ), f"Failed: {transport_name} Connection did not negotiate X25519MLKEM768! Negotiated: {negotiated_group}" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to check for X25519MLKEM768 exectly? or *MLKEM*? The assertion and comments seem to suggest different things
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We check "MLKEM" in negotiated_group instead of exact string matching (== "X25519MLKEM768") to ensure compatibility across different TLS implementations (BoringSSL on gRPC vs OpenSSL on REST), which format group strings slightly differently (e.g. X25519MLKEM768 vs X25519MLKEM768Draft00).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gemini says there is also secp256r1MLKEM768. It seems like that's another post-quantum algorithm, but I'm not sure if that's one we want to support or not. Maybe we should either change the comments to be more general, or the assertion to be more specific?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly, these tests run against Showcase server so it doesn't really matter much. However, current goal is that we support a Hybrid group which we'll default too. In future, we'll default to a PURE PQC group. So in reality, the backend will only return what they're defaulting too. Keeping it generic is more robust for us. |
||
|
|
||
|
|
||
| def test_pqc_grpc(intercepted_echo_grpc): | ||
| """Verifies that the gRPC client library negotiates PQC (X25519MLKEM768) with Showcase server.""" | ||
| # TODO(https://github.com/googleapis/google-cloud-python/issues/17752): | ||
| # Remove this check once grpcio >= 1.83.0 is enforced across all client libraries. | ||
| if Version(grpc.__version__) < Version("1.83.0rc0"): | ||
| # TODO(https://github.com/googleapis/google-cloud-python/issues/17751): | ||
| # Update the version in the check above to `1.83.0` once released. | ||
| pytest.skip(f"gRPC PQC negotiation requires grpcio >= 1.83.0 (current: {grpc.__version__})") | ||
|
|
||
| client, interceptor = intercepted_echo_grpc | ||
| response = client.echo(request=showcase.EchoRequest(content="Verify PQC connection.")) | ||
| assert response.content == "Verify PQC connection." | ||
| _verify_pqc_metadata(interceptor, "grpc") | ||
|
|
||
|
|
||
| def test_pqc_rest(intercepted_echo_rest): | ||
| """Verifies that the REST client library negotiates PQC (X25519MLKEM768) with Showcase server.""" | ||
| client, interceptor = intercepted_echo_rest | ||
| response = client.echo(request=showcase.EchoRequest(content="Verify PQC connection.")) | ||
| assert response.content == "Verify PQC connection." | ||
| _verify_pqc_metadata(interceptor, "rest") | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_pqc_grpc_async(intercepted_echo_grpc_async): | ||
| """Verifies that the async gRPC client library negotiates PQC (X25519MLKEM768) with Showcase server.""" | ||
| # TODO(https://github.com/googleapis/google-cloud-python/issues/17752): | ||
| # Remove this check once grpcio >= 1.83.0 is enforced across all client libraries. | ||
| if Version(grpc.__version__) < Version("1.83.0rc0"): | ||
| # TODO(https://github.com/googleapis/google-cloud-python/issues/17751): | ||
| # Update the version in the check above to `1.83.0` once released. | ||
| pytest.skip( | ||
| f"gRPC PQC negotiation requires grpcio >= 1.83.0 (current: {grpc.__version__})" | ||
| ) | ||
|
|
||
| client, interceptor = intercepted_echo_grpc_async | ||
| response = await client.echo( | ||
| request=showcase.EchoRequest(content="Verify PQC connection.") | ||
| ) | ||
| assert response.content == "Verify PQC connection." | ||
| _verify_pqc_metadata(interceptor, "grpc_asyncio") | ||
Uh oh!
There was an error while loading. Please reload this page.