Skip to content

test: add post-quantum cryptography conformance tests for showcase - #1351

Open
torreypayne wants to merge 5 commits into
pqc-tls-validationfrom
pqc-validation-tests
Open

torreypayne wants to merge 5 commits into
pqc-tls-validationfrom
pqc-validation-tests

Conversation

@torreypayne

@torreypayne torreypayne commented Sep 15, 2026 •

Copy link
Copy Markdown
Member

Adds shared/test/showcase/pqc_test.rb, proving Ruby clients negotiate a post-quantum (ML-KEM) key exchange against Showcase over both transports.

Ruby never performs the key exchange itself — gRPC delegates to BoringSSL vendored in the grpc gem, REST to system OpenSSL.

The suite therefore asserts on what the server observed, via the x-showcase-tls-group and x-showcase-tls-client-supported-groups metadata in every response. Python, Node, Java, C#, and C++ assert the same way.

Two scenarios per transport: default negotiation, and fallback against a classical-only server.

Reviewer notes

  • Groups match on the MLKEM substring, as in gax-dotnet#909. Each test checks what the client offered before what was negotiated, so fallback tests fail against a client that lost PQC entirely.
  • REST never skips; the host decides the expected outcome. OpenSSL >= 3.5 must negotiate ML-KEM; below 3.5 must negotiate X25519. SHOWCASE_REQUIRE_REST_PQC=1 only asserts the host is >= 3.5 — chore(ci): provision an OpenSSL 3.5 image and hard-assert REST post-quantum key exchange #1352 sets it on a 3.5 image.
  • with_showcase_tls_groups lives in test_helper.rb and fails if its class uses parallelize_me!, since it swaps process-wide SSL_CERT_FILE.
  • normalize_headers fails loudly when TLS metadata is absent, so plaintext cannot silently no-op the suite.

Companion: ruby-core-libraries#73 raises the gapic-common grpc floor.
Design: go/client-libraries:ruby-pqc · Parent: go/cloudsdk-pqc-ruby

@torreypayne
torreypayne force-pushed the pqc-validation-tests branch 2 times, most recently from 4330712 to a03c2b9 Compare September 16, 2026 19:38
@torreypayne
torreypayne added this pull request to stack #1353 September 16, 2026 20:00
@torreypayne
torreypayne force-pushed the pqc-validation-tests branch 2 times, most recently from bc07fca to 8279a21 Compare September 17, 2026 17:20
@torreypayne
torreypayne removed this pull request from stack #1353 September 21, 2026 17:11
@torreypayne
torreypayne added this pull request to stack #1356 September 21, 2026 17:12
@torreypayne
torreypayne force-pushed the pqc-validation-tests branch 3 times, most recently from b0003eb to 63bab3b Compare September 21, 2026 20:50
@torreypayne
torreypayne marked this pull request as ready for review September 21, 2026 20:50
@torreypayne
torreypayne requested a review from a team as a code owner September 21, 2026 20:50

@amanda-tarafa amanda-tarafa left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly good, just some improvements I think.

Comment thread shared/test/showcase/pqc_test.rb Outdated
Comment thread shared/test/showcase/pqc_test.rb Outdated
Comment thread shared/test/showcase/pqc_test.rb Outdated
Comment thread shared/test/showcase/pqc_test.rb Outdated
Comment thread shared/test/showcase/pqc_test.rb Outdated
Comment thread shared/test/showcase/pqc_test.rb Outdated
Comment thread shared/test/showcase/pqc_test.rb
Comment thread shared/test/showcase/test_helper.rb
Adds a dedicated suite that proves the generated Ruby clients negotiate
X25519MLKEM768 with the Showcase server over both transports.

Assertions read the TLS metadata that Showcase reflects onto every response
(x-showcase-tls-group and x-showcase-tls-client-supported-groups) rather than
inspecting CRuby's internal OpenSSL structures, whose layout is not stable
across Ruby releases or platforms.

Covered scenarios:
- gRPC and REST negotiate the hybrid post-quantum group and advertise it in
  their ClientHello.
- Both transports degrade cleanly to classical X25519 when the server offers
  only classical groups. These also assert the client still advertised
  X25519MLKEM768: without that, the test would pass just as happily against a
  client that had lost post-quantum support altogether.

The classical-only case needs a second Showcase process, since --tls-groups
applies to a whole server. That auxiliary process mints a certificate authority
of its own, so the test points SSL_CERT_FILE at the new CA for the duration of
the block and builds explicit gRPC credentials from it.

REST cannot be held to post-quantum key exchange unconditionally. It delegates
to the host's OpenSSL, and ML-KEM only exists from OpenSSL 3.5 onward, while
GitHub Actions ubuntu-latest ships 3.0.13. Skipping on older hosts would leave
the REST transport unexercised in CI entirely, which is a permanently green
check that verifies nothing. Instead the negotiated group must be present
(proving the connection was genuinely TLS), must be either X25519MLKEM768 or
classical X25519, and must be a group the client actually offered. Setting
SHOWCASE_REQUIRE_REST_PQC=1 promotes this into a strict post-quantum assertion.

Group membership is tested against the split supported-groups list rather than
the raw header value, because "X25519" is a substring of "X25519MLKEM768" and a
string containment check could therefore never fail.

This mirrors the merged conformance test in gax-php. Ruby and PHP are the only
Cloud SDK languages whose REST transport binds to the system OpenSSL instead of
a vendored TLS stack, so they are the only two that cannot hard-assert
post-quantum key exchange on a stock runner.
… mode

test_rest_falls_back_to_classical_key_exchange guarded its "client still
advertises X25519MLKEM768" assertion with REQUIRE_REST_PQC, the strict-mode
policy flag, while the comment directly above justifies that guard in terms of
host OpenSSL capability. Two independent predicates: they coincide only because
CI sets the environment variable on exactly the one PQC-capable image.

Where they diverge - a workstation on OpenSSL >= 3.5, or CI itself once
ubuntu-latest is upgraded and the pqc-rest job is retired - the assertion
silently disappears and the test degrades to "negotiated X25519", which the
gRPC twin's comment explains proves nothing: a client that had lost
post-quantum support entirely produces an identical result.

Verified by withholding ML-KEM from the client via OPENSSL_CONF on an OpenSSL
3.5.5 image with strict mode off. Before: 59 runs, 0 failures. After: 1
failure, raised by this assertion.

@quartzmo quartzmo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments in this PR are really helpful, great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants