|
17 | 17 | package com.google.showcase.v1beta1.it; |
18 | 18 |
|
19 | 19 | import static com.google.common.truth.Truth.assertThat; |
20 | | -import static org.junit.jupiter.api.Assumptions.assumeTrue; |
21 | 20 |
|
22 | 21 | import com.google.api.client.http.javanet.NetHttpTransport; |
23 | 22 | import com.google.api.gax.core.NoCredentialsProvider; |
|
38 | 37 | import com.google.showcase.v1beta1.EchoResponse; |
39 | 38 | import com.google.showcase.v1beta1.EchoSettings; |
40 | 39 | import io.grpc.Channel; |
41 | | -import io.grpc.ChannelCredentials; |
42 | 40 | import io.grpc.ClientCall; |
43 | 41 | import io.grpc.ClientInterceptor; |
44 | 42 | import io.grpc.ForwardingClientCall; |
45 | 43 | import io.grpc.ForwardingClientCallListener; |
46 | | -import io.grpc.Grpc; |
47 | 44 | import io.grpc.ManagedChannel; |
48 | 45 | import io.grpc.Metadata; |
49 | 46 | import io.grpc.MethodDescriptor; |
50 | | -import io.grpc.TlsChannelCredentials; |
51 | | -import java.io.File; |
52 | | -import java.io.InputStream; |
53 | | -import java.nio.file.Files; |
54 | | -import java.nio.file.Paths; |
55 | | -import java.security.KeyStore; |
56 | | -import java.security.Security; |
57 | | -import java.security.cert.Certificate; |
58 | | -import java.security.cert.CertificateFactory; |
| 47 | +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; |
| 48 | +import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; |
| 49 | +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; |
| 50 | +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; |
| 51 | +import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; |
| 52 | +import java.security.Provider; |
59 | 53 | import java.util.Collections; |
60 | 54 | import java.util.concurrent.TimeUnit; |
61 | 55 | import org.conscrypt.Conscrypt; |
|
64 | 58 |
|
65 | 59 | public class ITPqc { |
66 | 60 |
|
67 | | - private static String caCertPath; |
68 | | - private static String grpcEndpoint; |
69 | | - private static String httpjsonEndpoint; |
70 | | - private static boolean hasCert; |
| 61 | + private static final String GRPC_ENDPOINT = "localhost:7470"; |
| 62 | + private static final String HTTPJSON_ENDPOINT = "https://localhost:7470"; |
71 | 63 |
|
72 | 64 | @BeforeAll |
73 | 65 | static void setUp() { |
74 | | - caCertPath = System.getProperty("showcase.ca.cert", "../../certs/ca.crt"); |
75 | | - grpcEndpoint = System.getProperty("showcase.secure-grpc.endpoint", "localhost:7470"); |
76 | | - httpjsonEndpoint = |
77 | | - System.getProperty("showcase.secure-httpjson.endpoint", "https://localhost:7470"); |
78 | | - |
79 | | - File certFile = new File(caCertPath); |
80 | | - hasCert = certFile.exists() && certFile.isFile(); |
81 | | - |
82 | 66 | // Force Conscrypt and OpenJDK to prefer X25519MLKEM768 for TLS 1.3 |
83 | 67 | System.setProperty("jdk.tls.namedGroups", "X25519MLKEM768,X25519,secp256r1"); |
84 | | - |
85 | | - // Register Conscrypt provider if available and not already registered |
86 | | - if (hasCert) { |
87 | | - try { |
88 | | - if (Security.getProvider("Conscrypt") == null) { |
89 | | - Security.insertProviderAt(Conscrypt.newProvider(), 1); |
90 | | - } |
91 | | - } catch (Throwable t) { |
92 | | - System.err.println("Failed to register Conscrypt provider: " + t.getMessage()); |
93 | | - } |
94 | | - } |
95 | 68 | } |
96 | 69 |
|
97 | 70 | @Test |
98 | 71 | void testGrpcPqc() throws Exception { |
99 | | - assumeTrue(hasCert, "CA Certificate not found at " + caCertPath + ". Skipping gRPC PQC test."); |
| 72 | + // Build insecure Netty SslContext to bypass certificate validation for testing |
| 73 | + SslContext sslContext = GrpcSslContexts.configure( |
| 74 | + SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)).build(); |
100 | 75 |
|
101 | | - // Create channel credentials trusting the custom CA |
102 | | - ChannelCredentials creds = |
103 | | - TlsChannelCredentials.newBuilder().trustManager(new File(caCertPath)).build(); |
104 | | - |
105 | | - ManagedChannel channel = Grpc.newChannelBuilder(grpcEndpoint, creds).build(); |
| 76 | + ManagedChannel channel = |
| 77 | + NettyChannelBuilder.forTarget(GRPC_ENDPOINT).sslContext(sslContext).build(); |
106 | 78 | TransportChannel transportChannel = GrpcTransportChannel.create(channel); |
107 | 79 |
|
108 | 80 | GrpcHeaderCapturingInterceptor interceptor = new GrpcHeaderCapturingInterceptor(); |
@@ -153,30 +125,15 @@ void testGrpcPqc() throws Exception { |
153 | 125 |
|
154 | 126 | @Test |
155 | 127 | void testHttpJsonPqc() throws Exception { |
156 | | - assumeTrue( |
157 | | - hasCert, "CA Certificate not found at " + caCertPath + ". Skipping HttpJson PQC test."); |
158 | | - |
159 | | - // Build custom TrustManager trusting the CA cert |
160 | | - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); |
161 | | - trustStore.load(null, null); |
162 | | - CertificateFactory cf = CertificateFactory.getInstance("X.509"); |
163 | | - try (InputStream is = Files.newInputStream(Paths.get(caCertPath))) { |
164 | | - Certificate cert = cf.generateCertificate(is); |
165 | | - trustStore.setCertificateEntry("showcase-ca", cert); |
166 | | - } |
167 | | - |
168 | | - // Since Conscrypt was registered at position 1 in setUp(), |
169 | | - // trustCertificates will resolve SSLContext using Conscrypt, |
170 | | - // and NetHttpTransport will automatically wrap the socket factory to enforce PQC. |
171 | | - NetHttpTransport transport = |
172 | | - new NetHttpTransport.Builder().trustCertificates(trustStore).build(); |
| 128 | + // Build NetHttpTransport with certificate validation disabled |
| 129 | + NetHttpTransport transport = new NetHttpTransport.Builder().doNotValidateCertificate().build(); |
173 | 130 |
|
174 | 131 | HttpJsonHeaderCapturingInterceptor interceptor = new HttpJsonHeaderCapturingInterceptor(); |
175 | 132 |
|
176 | 133 | InstantiatingHttpJsonChannelProvider transportChannelProvider = |
177 | 134 | EchoSettings.defaultHttpJsonTransportProviderBuilder() |
178 | 135 | .setHttpTransport(transport) |
179 | | - .setEndpoint(httpjsonEndpoint) |
| 136 | + .setEndpoint(HTTPJSON_ENDPOINT) |
180 | 137 | .setInterceptorProvider(() -> Collections.singletonList(interceptor)) |
181 | 138 | .build(); |
182 | 139 |
|
@@ -209,6 +166,52 @@ void testHttpJsonPqc() throws Exception { |
209 | 166 | } |
210 | 167 | } |
211 | 168 |
|
| 169 | + @Test |
| 170 | + void testHttpJsonPqc_withExplicitSecurityProvider() throws Exception { |
| 171 | + Provider explicitConscryptProvider = Conscrypt.newProvider(); |
| 172 | + |
| 173 | + // Build NetHttpTransport specifying the Conscrypt provider explicitly |
| 174 | + NetHttpTransport transport = |
| 175 | + new NetHttpTransport.Builder() |
| 176 | + .setSecurityProvider(explicitConscryptProvider) |
| 177 | + .doNotValidateCertificate() |
| 178 | + .build(); |
| 179 | + |
| 180 | + HttpJsonHeaderCapturingInterceptor interceptor = new HttpJsonHeaderCapturingInterceptor(); |
| 181 | + |
| 182 | + InstantiatingHttpJsonChannelProvider transportChannelProvider = |
| 183 | + EchoSettings.defaultHttpJsonTransportProviderBuilder() |
| 184 | + .setHttpTransport(transport) |
| 185 | + .setEndpoint(HTTPJSON_ENDPOINT) |
| 186 | + .setInterceptorProvider(() -> Collections.singletonList(interceptor)) |
| 187 | + .build(); |
| 188 | + |
| 189 | + EchoSettings settings = |
| 190 | + EchoSettings.newHttpJsonBuilder() |
| 191 | + .setCredentialsProvider(NoCredentialsProvider.create()) |
| 192 | + .setTransportChannelProvider(transportChannelProvider) |
| 193 | + .build(); |
| 194 | + |
| 195 | + try (EchoClient client = EchoClient.create(settings)) { |
| 196 | + EchoResponse response = |
| 197 | + client.echo( |
| 198 | + EchoRequest.newBuilder().setContent("pqc-httpjson-explicit-provider-test").build()); |
| 199 | + assertThat(response.getContent()).isEqualTo("pqc-httpjson-explicit-provider-test"); |
| 200 | + |
| 201 | + HttpJsonMetadata capturedHeaders = interceptor.getCapturedHeaders(); |
| 202 | + assertThat(capturedHeaders).isNotNull(); |
| 203 | + |
| 204 | + String negotiatedGroup = getSingleHeaderString(capturedHeaders, "x-showcase-tls-group"); |
| 205 | + assertThat(negotiatedGroup).isEqualTo("X25519MLKEM768"); |
| 206 | + |
| 207 | + String tlsVersion = getSingleHeaderString(capturedHeaders, "x-showcase-tls-version"); |
| 208 | + assertThat(tlsVersion).isEqualTo("TLS 1.3"); |
| 209 | + |
| 210 | + String tlsCipher = getSingleHeaderString(capturedHeaders, "x-showcase-tls-cipher"); |
| 211 | + assertThat(tlsCipher).isEqualTo("TLS_AES_128_GCM_SHA256"); |
| 212 | + } |
| 213 | + } |
| 214 | + |
212 | 215 | private static class GrpcHeaderCapturingInterceptor implements ClientInterceptor { |
213 | 216 | private Metadata capturedHeaders; |
214 | 217 |
|
|
0 commit comments