Skip to content

Commit 2d0fe09

Browse files
committed
wip
1 parent f476283 commit 2d0fe09

2 files changed

Lines changed: 67 additions & 25 deletions

File tree

packages/gapic-generator/tests/system/test_pqc.py

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,29 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import os
1615
import pytest
1716
import requests
1817
from google import showcase
1918

19+
2020
@pytest.fixture
2121
def run_pqc_test(use_mtls):
2222
if not use_mtls:
2323
pytest.skip("PQC integration test requires mTLS (--mtls flag) to be enabled.")
2424

25+
2526
@pytest.mark.parametrize(
2627
"transport_fixture",
2728
["intercepted_echo_grpc", "intercepted_echo_rest"]
2829
)
2930
def test_pqc_negotiated_group(run_pqc_test, request, transport_fixture):
30-
"""Verifies that the generated client library negotiates PQC with the Showcase server."""
31+
"""Verifies that the generated client library negotiates PQC (X25519MLKEM768) with Showcase server."""
3132
client, interceptor = request.getfixturevalue(transport_fixture)
32-
33-
# Make secure call using the standard client library fixture
33+
34+
# Make secure call using standard GAPIC client library fixture
3435
response = client.echo(request=showcase.EchoRequest(content="Verify PQC connection."))
3536
assert response.content == "Verify PQC connection."
36-
37+
3738
# Extract negotiated group and supported groups from response headers
3839
negotiated_group = None
3940
supported_groups = None
@@ -42,59 +43,56 @@ def test_pqc_negotiated_group(run_pqc_test, request, transport_fixture):
4243
negotiated_group = value
4344
elif key.lower() == "x-showcase-tls-client-supported-groups":
4445
supported_groups = value
45-
46+
4647
assert negotiated_group is not None, "Failed: Showcase server did not return negotiated TLS group header."
4748
assert supported_groups is not None, "Failed: Showcase server did not return client advertised supported groups."
48-
49+
4950
print(f"\n[PQC Verification] ({transport_fixture}) Negotiated TLS Group: {negotiated_group}")
5051
print(f"[PQC Verification] ({transport_fixture}) Client Advertised Supported Groups: {supported_groups}")
51-
52-
# Enforce PQC compliance (this will fail if not using MLKEM/Kyber)
52+
53+
# Enforce PQC compliance (X25519MLKEM768 or Kyber)
5354
assert "MLKEM" in negotiated_group or "Kyber" in negotiated_group, \
5455
f"Failed: {transport_fixture} Connection is NOT PQC-compliant! Negotiated: {negotiated_group}"
5556

5657

5758
def test_google_auth_transport_pqc(run_pqc_test):
58-
"""Verifies that the google-auth HTTP transport adapter negotiates PQC with the Showcase server."""
59+
"""Verifies that google-auth transport adapter negotiates PQC (X25519MLKEM768) with Showcase server."""
5960
import google.auth.transport.requests
60-
from google.protobuf.json_format import MessageToJson
6161
from conftest import HostNameIgnoringAdapter
6262

63-
# 1. Initialize a standard requests Session with mTLS certs
63+
# 1. Initialize requests Session with mTLS certs
6464
session = requests.Session()
6565
cert_path = "/usr/local/google/home/omairn/git/googleapis/google-cloud-python-dev2/packages/gapic-generator/tests/cert/mtls.crt"
6666
key_path = "/usr/local/google/home/omairn/git/googleapis/google-cloud-python-dev2/packages/gapic-generator/tests/cert/mtls.key"
6767

6868
session.verify = cert_path
6969
session.cert = (cert_path, key_path)
70-
71-
# Bypass localhost hostname mismatch
7270
session.mount("https://", HostNameIgnoringAdapter())
7371

74-
# 2. Wrap it in google-auth's Transport Request adapter
72+
# 2. Wrap session in google-auth transport adapter
7573
auth_transport = google.auth.transport.requests.Request(session=session)
7674

77-
# 3. Serialize the request body using the official protobuf JSON serializer
75+
# 3. Serialize request body
7876
req = showcase.EchoRequest(content="Verify google-auth transport PQC connection.")
79-
body = MessageToJson(req, including_default_value_fields=True).encode("utf-8")
77+
body = showcase.EchoRequest.to_json(req, including_default_value_fields=False).encode("utf-8")
8078

81-
# 4. Make secure call using the google-auth transport adapter
79+
# 4. Execute request through google-auth's transport layer
8280
url = "https://localhost:7469/v1beta1/echo:echo"
83-
method = "POST"
84-
headers = {"Content-Type": "application/json"}
81+
headers = {
82+
"Content-Type": "application/json",
83+
"x-goog-api-client": "gapic/1.0 rest/1.0",
84+
}
8585

86-
# Execute the request through google-auth's transport layer
87-
response = auth_transport(url=url, method=method, body=body, headers=headers)
88-
assert response.status == 200
86+
response = auth_transport(url=url, method="POST", body=body, headers=headers)
87+
assert response.status == 200, f"Failed: status={response.status}, body={response.data}"
8988

90-
# 5. Extract TLS group from response headers returned by Showcase
89+
# 5. Extract and verify negotiated TLS group returned by Showcase
9190
negotiated_group = response.headers.get("x-showcase-tls-group")
9291
supported_groups = response.headers.get("x-showcase-tls-client-supported-groups")
9392

9493
assert negotiated_group is not None, "Failed: Showcase server did not return negotiated TLS group header."
9594
print(f"\n[google-auth Transport PQC] Negotiated TLS Group: {negotiated_group}")
9695
print(f"[google-auth Transport PQC] Client Advertised Supported Groups: {supported_groups}")
9796

98-
# Assert PQC compliance
9997
assert "MLKEM" in negotiated_group or "Kyber" in negotiated_group, \
10098
f"Failed: google-auth Transport is NOT PQC-compliant! Negotiated: {negotiated_group}"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import cryptography
16+
import pytest
17+
from packaging.version import Version
18+
19+
20+
def test_cryptography_pqc_mlkem_support():
21+
"""Verifies that the cryptography package installed in google-auth supports Post-Quantum Cryptography (ML-KEM / FIPS 203)."""
22+
# Attempt to import ML-KEM (FIPS 203) introduced in cryptography 44.0.0
23+
try:
24+
from cryptography.hazmat.primitives.asymmetric import mlkem
25+
except ImportError:
26+
pytest.fail(
27+
f"PQC Compliance Failure: cryptography version {cryptography.__version__} does not support ML-KEM (FIPS 203). "
28+
f"google-auth requires cryptography >= 44.0.0 for PQC support."
29+
)
30+
31+
# 1. Generate ML-KEM-768 (FIPS 203) private key and derive public key
32+
private_key = mlkem.MLKEM768PrivateKey.generate()
33+
public_key = private_key.public_key()
34+
assert isinstance(private_key, mlkem.MLKEM768PrivateKey)
35+
assert isinstance(public_key, mlkem.MLKEM768PublicKey)
36+
37+
# 2. Perform Key Encapsulation (sender generates shared secret + ciphertext)
38+
shared_secret_sender, ciphertext = public_key.encapsulate()
39+
assert len(ciphertext) > 0
40+
assert len(shared_secret_sender) > 0
41+
42+
# 3. Perform Key Decapsulation (receiver recovers shared secret from ciphertext)
43+
shared_secret_receiver = private_key.decapsulate(ciphertext)
44+
assert shared_secret_receiver == shared_secret_sender

0 commit comments

Comments
 (0)