Skip to content

chore: [wip] PQC POC 2#13203

Draft
diegomarquezp wants to merge 3 commits into
mainfrom
chore/pqc-poc-2
Draft

chore: [wip] PQC POC 2#13203
diegomarquezp wants to merge 3 commits into
mainfrom
chore/pqc-poc-2

Conversation

@diegomarquezp
Copy link
Copy Markdown
Contributor

No description provided.

TAG=agy
CONV=0ade5891-3c8d-4e27-a240-b1a8cd6a0b0c
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces Post-Quantum Cryptography (PQC) support across the Java SDK by integrating Bouncy Castle and configuring PQC-hardened SSL contexts for gRPC and HTTP/JSON transports. Key changes include the addition of a pqc-test module, reflection-based configuration for Netty channel builders, and updates to OAuth2Utils and InstantiatingHttpJsonChannelProvider. Feedback identifies issues with potential initialization errors in OAuth2Utils, the use of a SNAPSHOT dependency version, and performance overhead from repeated reflection lookups. Suggestions were also provided for improving exception handling, ensuring logic consistency in transport creation, and cleaning up test provider registrations.

.setSslSocketFactory(SslUtils.getTlsSslContext().getSocketFactory())
.build();
} catch (GeneralSecurityException e) {
throw new RuntimeException("Failed to initialize PQC-hardened HTTP transport", e);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Throwing a RuntimeException in a static initializer block will cause an ExceptionInInitializerError, making the OAuth2Utils class completely unusable if TLS initialization fails. This is inconsistent with the graceful degradation approach used in InstantiatingGrpcChannelProvider. Consider logging the error and falling back to a default transport if PQC initialization is not strictly mandatory.

<javax.annotation-api.version>1.3.2</javax.annotation-api.version>
<grpc.version>1.81.0</grpc.version>
<google.http-client.version>2.1.0</google.http-client.version>
<google.http-client.version>2.1.1-SNAPSHOT</google.http-client.version>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using a SNAPSHOT version for google-http-client makes the build non-deterministic and is not suitable for a production release. Ensure this is updated to a stable version before merging.

setSslContextOnBuilder(builder, sslContext, isShaded);
return builder;
}
} catch (Exception e) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Catching a generic Exception and silently ignoring it can mask legitimate configuration issues. It is better to catch specific exceptions (e.g., ReflectiveOperationException, RuntimeException) and log a warning to aid in debugging if PQC configuration fails.

Suggested change
} catch (Exception e) {
} catch (ReflectiveOperationException | RuntimeException e) {

Comment on lines +868 to +890
private Object buildOpenSslContext(boolean isShaded, String[] groups) throws Exception {
String prefix = isShaded ? "io.grpc.netty.shaded." : "";
Class<?> grpcSslContextsClass = Class.forName(prefix + "io.grpc.netty.GrpcSslContexts");
Class<?> sslContextBuilderClass = Class.forName(prefix + "io.netty.handler.ssl.SslContextBuilder");
Class<?> openSslContextOptionClass = Class.forName(prefix + "io.netty.handler.ssl.OpenSslContextOption");
Class<?> sslContextOptionClass = Class.forName(prefix + "io.netty.handler.ssl.SslContextOption");

// GrpcSslContexts.forClient() -> returns SslContextBuilder
java.lang.reflect.Method forClientMethod = grpcSslContextsClass.getMethod("forClient");
Object sslContextBuilder = forClientMethod.invoke(null);

// OpenSslContextOption.GROUPS
java.lang.reflect.Field groupsField = openSslContextOptionClass.getDeclaredField("GROUPS");
Object groupsOption = groupsField.get(null);

// SslContextBuilder.option(SslContextOption, Object)
java.lang.reflect.Method optionMethod = sslContextBuilderClass.getMethod("option", sslContextOptionClass, Object.class);
optionMethod.invoke(sslContextBuilder, groupsOption, groups);

// SslContextBuilder.build() -> returns SslContext
java.lang.reflect.Method buildMethod = sslContextBuilderClass.getMethod("build");
return buildMethod.invoke(sslContextBuilder);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The reflection-based lookups for classes, methods, and fields are performed every time a channel is created. This introduces unnecessary overhead. These should be resolved once and cached in static fields to improve performance.

Comment on lines 189 to +209
HttpTransport createHttpTransport() throws IOException, GeneralSecurityException {
if (mtlsProvider == null) {
return null;
}
if (certificateBasedAccess.useMtlsClientCertificate()) {
// 1. Get the scope-specific PQC-hardened SSLContext utilizing Bouncy Castle.
SSLContext sslContext = com.google.api.client.util.SslUtils.getTlsSslContext();

// 2. Initialize the NetHttpTransport builder pre-configured with our PQC SSL context.
NetHttpTransport.Builder builder = new NetHttpTransport.Builder()
.setSslSocketFactory(sslContext.getSocketFactory());

// 3. Verify if mTLS is supported and explicitly requested in the current client session.
if (mtlsProvider != null && certificateBasedAccess.useMtlsClientCertificate()) {
// 4. Retrieve the mutual TLS client key store from the session-specific mtlsProvider.
KeyStore mtlsKeyStore = mtlsProvider.getKeyStore();
// 5. Ensure key store is valid before configuring mutual TLS client certificates.
if (mtlsKeyStore != null) {
return new NetHttpTransport.Builder().trustCertificates(null, mtlsKeyStore, "").build();
// 6. Configure the mutual TLS certificates while preserving the PQC SSL context.
builder.trustCertificates(null, mtlsKeyStore, "");
}
}
return null;

// 7. Return the compiled and PQC-hardened NetHttpTransport instance.
return builder.build();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The original implementation of createHttpTransport returned null if mtlsProvider was null. The new implementation always returns a NetHttpTransport instance. This change in behavior might bypass default transport configurations or logic that expects a null return when mTLS is not active. Verify if this change was intentional for all HTTP/JSON transports.

Comment on lines +147 to +149
java.lang.reflect.Method getTrustManagersMethod = tmFactoryClass.getMethod("getTrustManagers");
// wait, insecure TM factory has getTrustManagers? Actually it inherits from SimpleTrustManagerFactory which has getTrustManagers? No, javax.net.ssl.TrustManagerFactory has getTrustManagers()
// Netty's InsecureTrustManagerFactory extends SimpleTrustManagerFactory. We can just pass the TrustManagerFactory itself to SslContextBuilder.trustManager(TrustManagerFactory)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The getTrustManagersMethod is reflectively looked up but never used, and the accompanying comments seem to be internal notes. These should be removed to clean up the test code.

if (httpServer != null) httpServer.stop(0);
if (grpcServer != null) grpcServer.shutdown();
// Remove BC JCA provider on stop
Security.removeProvider("BC");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The stop() method removes the "BC" provider but leaves the "BCJSSE" provider registered. Both should be removed to ensure a clean state for subsequent tests.

    Security.removeProvider("BCJSSE");
    Security.removeProvider("BC");

…ranch chore/pqc-poc-2

TAG=agy
CONV=0ade5891-3c8d-4e27-a240-b1a8cd6a0b0c
TAG=agy
CONV=0ade5891-3c8d-4e27-a240-b1a8cd6a0b0c
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.

1 participant