Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions docs/post_quantum_cryptography_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
# Post-Quantum Cryptography (PQC) User Guide for HTTP/JSON Java Client Libraries

## 1. The Quantum Threat & Why PQC is Critical

Traditional TLS public-key encryption (such as RSA and ECDH) is vulnerable to future decryption by quantum computers.

- **The Risk ("Store-Now, Decrypt-Later")**: Adversaries can intercept and store encrypted network traffic today with the intent to decrypt it once cryptographically relevant quantum computers become available.
- **The Consequence**: Without Post-Quantum Cryptography (PQC), sensitive data transmitted today—such as credentials, financial records, and customer data—is at risk of retroactive decryption in the future.
- **The Solution (Hybrid PQC)**: Google Cloud HTTP/JSON Java client libraries support **Hybrid PQC Key Exchange** (such as `X25519MLKEM768`), combining a classical ECDH algorithm (like `X25519`) with a NIST-standardized Post-Quantum Key Encapsulation Mechanism (like `ML-KEM-768`, FIPS 203). This protects encrypted traffic against both present-day and future quantum threats without sacrificing existing security.

---

## 2. HTTP/JSON (REST) Client Library Support

Google Cloud Java client libraries (`gax-httpjson`) use **Conscrypt by default** to achieve Post-Quantum Cryptography (PQC) for **HTTP/JSON** (REST) transport whenever native BoringSSL libraries are supported on the runtime environment.

> [!WARNING]
> **User Responsibility for Conscrypt Compatibility**:
> It is the user's responsibility to ensure that their runtime environment supports Conscrypt native libraries if they want to use the default PQC configuration. Otherwise, users can opt to use alternative configurations (see **Section 2.7**). If Conscrypt cannot be initialized, the client library will silently fall back to standard JDK JSSE (`SunJSSE`), which on Java 8–20 has no Post-Quantum Cryptography support. See **Section 2.5 (Known Conscrypt Compatibility Issues)** for more information.

### 2.1 Minimum Required Versions

PQC enablement for HTTP/JSON transport requires compatible versions of `conscrypt-openjdk-uber`, `gax-httpjson`, and `google-http-client`:

> [!TIP]
> **Recommended BOM**:
> We recommend importing Google Cloud Java libraries using **`libraries-bom` version `26.86.0+`**, which automatically manages compatible dependency versions across all Google Cloud client libraries, GAX, and the Google HTTP Client.

| Library | Minimum Required Version | Role |
| :--- | :--- | :--- |
| **`conscrypt-openjdk-uber`** | `2.6.0+` | Provides BoringSSL native C engine and TLS 1.3 PQC hybrid named groups. |
| **`gax-httpjson`** | `2.83.0+` | Automatically registers Conscrypt as the TLS security provider and configures PQC named groups. |
| **`google-http-client`** | `2.2.0+` | Provides security provider registration and socket configurators on `NetHttpTransport.Builder`. |

### 2.2 Why Conscrypt?

Standard Java Development Kits (Java 8–20) do not natively support Post-Quantum Cryptography in their built-in TLS providers (`SunJSSE`). While native ML-KEM support is planned for **JDK 27+**, requiring all users to upgrade to JDK 27 is not feasible for most production environments.

**Conscrypt** (`conscrypt-openjdk-uber`) is the default `SecurityProvider` for Google Cloud Java client libraries because:
1. **Maximum Java & OS Compatibility**: Conscrypt wraps Google's BoringSSL cryptographic engine via JNI, enabling quantum-resistant TLS 1.3 handshakes across existing Java runtimes (**Java 8+**).
2. **Zero Runtime Configuration Required**: By bundling Conscrypt as an optional dependency, `gax-httpjson` delivers high-performance PQC out-of-the-box without requiring users to replace their JVM or upgrade their JDK.

### 2.3 How HTTP/JSON Clients and Google Cloud Servers Work Together

When you construct a Google Cloud HTTP/JSON service client, `gax-httpjson` registers Conscrypt on the Google HTTP Client (`NetHttpTransport`) to advertise PQC and classical groups in preference order:

- **PQC-Enabled Google Cloud Endpoints**: During the TLS 1.3 handshake, Google Cloud servers select `X25519MLKEM768` (#1 preference), establishing a quantum-resistant session.
- **Non-PQC Endpoints**: Endpoints that do not support PQC ignore unknown post-quantum identifiers and select the first compatible classical algorithm (such as `X25519`).
- **Platform Runtime Fallback**: If Conscrypt native libraries cannot load on the OS, the client logs at debug level (`FINE`) and falls back to standard JDK JSSE (`SunJSSE`) without emitting operational warnings.

```
+-------------------------------------------------------------------+
| GAPIC HTTP/JSON Client Request |
+-------------------------------------------------------------------+
|
Is Conscrypt JNI Available on Platform?
|
+----------------+----------------+
| |
[ YES ] [ NO ]
| |
v v
google-http-client uses Conscrypt Falls back to JDK JSSE
Offers PQC Hybrid + Classical Groups Offers Standard JDK Classical Groups
- Server selects 1st compatible group - Server negotiates Classical
- Negotiates X25519MLKEM768 on X25519 / secp256r1 via JDK TLS
Google Cloud Endpoints
- Automatically falls back to X25519
on older non-PQC servers
```

### 2.4 Supported Key Exchange Groups

Google Cloud HTTP/JSON client libraries configure Conscrypt to advertise the following named groups in preference order:

1. `X25519MLKEM768`
2. `SecP256r1MLKEM768`
3. `MLKEM1024`
4. `MLKEM768`
5. `X25519Kyber768Draft00` *(deprecated draft group kept for backward compatibility)*
6. `X25519`
7. `secp256r1`
8. `secp384r1`

For additional details on Conscrypt's cryptographic algorithms and capabilities, refer to the official [Conscrypt CAPABILITIES.md](https://github.com/google/conscrypt/blob/2.6.0/CAPABILITIES.md#supported-named-groups).

### 2.5 Known Conscrypt Compatibility Issues

Because Conscrypt relies on C native shared libraries (`conscrypt-openjdk-uber`) loaded via Java Native Interface (JNI), PQC support depends on OS platform compatibility. Note that the constraints below represent known common issues and are **not an exhaustive list** of Conscrypt platform requirements:

1. **System & GLIBC Compatibility Constraints**:
- **Linux glibc Versioning**: Conscrypt native C binaries require compatible C runtime (`glibc`) versions (such as `GLIBC_2.35+`). Older Linux distributions or lightweight images (such as Alpine Linux using `musl` libc) will fail to load native libraries (`UnsatisfiedLinkError`).
- **Restricted Filesystems**: Operating systems that mount `/tmp` with `noexec`, strict container security profiles, or environments blocking JNI library extraction will prevent Conscrypt from initializing.

2. **Graceful Fallback Behavior**:
- Whenever native library loading fails, `gax-httpjson` catches the error, logs at **`Level.FINE` (debug level)**, and safely falls back to standard JDK JSSE (`SunJSSE`):
```
FINE: Conscrypt native libraries not available. Falling back to JDK TLS.
```
- Your application will continue running normally using classical TLS provided by the JDK without emitting warnings in standard operational logs.

### 2.6 Verifying PQC in HTTP/JSON Client Libraries

You can verify that your Google Cloud HTTP/JSON Java client library is actively negotiating Post-Quantum Cryptography through debug logging. Note that the log messages and logger categories below apply specifically to HTTP/JSON (REST) client libraries.

To inspect whether Conscrypt successfully initialized or why it fell back to JDK TLS, enable debug logging (`Level.FINE`) for `com.google.api.gax.httpjson.HttpJsonConscryptUtils`:

- In `logging.properties`:
```properties
com.google.api.gax.httpjson.HttpJsonConscryptUtils.level = FINE
```
- When Conscrypt is unavailable or fails to initialize, it logs at `Level.FINE`:
```
FINE: Conscrypt native library unavailable. Falling back to default JDK TLS.
FINE: Conscrypt initialization failed with exception: java.lang.UnsatisfiedLinkError: ...
```
- When Conscrypt initializes successfully, no fallback messages appear in the `FINE` logs.

### 2.7 Custom & Alternative Configurations

If you need to disable PQC, force classical key exchange, bypass Conscrypt, or use a third-party security provider, you can customize the transport provider.

#### Alternative 1: Forcing Classical (Non-PQC) Key Exchange

To explicitly restrict key exchange to classical `X25519` (disabling post-quantum hybrid groups):

```java
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.gax.httpjson.HttpJsonConscryptUtils;
import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings;
import org.conscrypt.Conscrypt;

// Step 1: Create NetHttpTransport configured with explicit classical named groups
NetHttpTransport transport =
HttpJsonConscryptUtils.configureConscryptSecurityProvider(new NetHttpTransport.Builder())
.setSslSocketConfigurator(
socket -> {
if (Conscrypt.isConscrypt(socket)) {
try {
// Explicitly offer only classical X25519 (disabling PQC hybrid groups)
Conscrypt.setNamedGroups(socket, new String[] {"X25519"});
} catch (Exception e) {
// Ignore or log socket configuration failure
}
}
})
.build();

// Step 2: Build transport channel provider using the custom transport
InstantiatingHttpJsonChannelProvider transportChannelProvider =
SecretManagerServiceSettings.defaultHttpJsonTransportProviderBuilder()
.setHttpTransport(transport)
.build();

// Step 3: Instantiate client with settings
SecretManagerServiceSettings settings =
SecretManagerServiceSettings.newHttpJsonBuilder()
.setTransportChannelProvider(transportChannelProvider)
.build();

try (SecretManagerServiceClient client = SecretManagerServiceClient.create(settings)) {
// Client communicates using classical X25519 TLS 1.3
}
```

#### Alternative 2: Bypassing Conscrypt to Use Standard JDK JSSE

To bypass Conscrypt completely and use the standard JDK JSSE TLS provider:

```java
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings;

// Build a standard NetHttpTransport without GAX Conscrypt configuration
NetHttpTransport standardTransport = new NetHttpTransport.Builder().build();

InstantiatingHttpJsonChannelProvider transportProvider =
SecretManagerServiceSettings.defaultHttpJsonTransportProviderBuilder()
.setHttpTransport(standardTransport)
.build();

SecretManagerServiceSettings settings =
SecretManagerServiceSettings.newHttpJsonBuilder()
.setTransportChannelProvider(transportProvider)
.build();

try (SecretManagerServiceClient client = SecretManagerServiceClient.create(settings)) {
// Client communicates using standard JDK JSSE TLS
}
```

#### Alternative 3: Configuring Custom Security Providers

If your application requires a custom cryptographic provider (such as Bouncy Castle), you can configure it on a specific `NetHttpTransport` instance using `NetHttpTransport.Builder.setSecurityProvider(...)` and `.setSslSocketConfigurator(...)`:

```java
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import com.google.cloud.secretmanager.v1.SecretManagerServiceSettings;
import java.security.Provider;

// Step 1: Instantiate custom security provider
Provider customProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider();

// Step 2: Configure NetHttpTransport with custom security provider and SSLSocketConfigurator
NetHttpTransport customTransport =
new NetHttpTransport.Builder()
.setSecurityProvider(customProvider)
.setSslSocketConfigurator(
socket -> {
// Configure custom SSLSocket options (e.g., cipher suites, protocols, or named groups)
})
Comment on lines +210 to +217

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

NetHttpTransport.Builder does not have a setSecurityProvider method. To use a custom security provider, you should configure an SSLContext with the custom provider and set the SSLSocketFactory on the builder.

Suggested change
// Step 2: Configure NetHttpTransport with custom security provider and SSLSocketConfigurator
NetHttpTransport customTransport =
new NetHttpTransport.Builder()
.setSecurityProvider(customProvider)
.setSslSocketConfigurator(
socket -> {
// Configure custom SSLSocket options (e.g., cipher suites, protocols, or named groups)
})
javax.net.ssl.SSLContext sslContext;
try {
sslContext = javax.net.ssl.SSLContext.getInstance("TLS", customProvider);
sslContext.init(null, null, null);
} catch (Exception e) {
throw new RuntimeException("Failed to initialize SSLContext with custom provider", e);
}
NetHttpTransport customTransport =
new NetHttpTransport.Builder()
.setSslSocketFactory(sslContext.getSocketFactory())
.setSslSocketConfigurator(
socket -> {
// Configure custom SSLSocket options (e.g., cipher suites, protocols, or named groups)
})
.build();

.build();

// Step 3: Build transport provider and service client
InstantiatingHttpJsonChannelProvider transportProvider =
SecretManagerServiceSettings.defaultHttpJsonTransportProviderBuilder()
.setHttpTransport(customTransport)
.build();

SecretManagerServiceSettings settings =
SecretManagerServiceSettings.newHttpJsonBuilder()
.setTransportChannelProvider(transportProvider)
.build();

try (SecretManagerServiceClient client = SecretManagerServiceClient.create(settings)) {
// Client communicates using custom security provider scoped strictly to this transport
}
```

---

## 3. Addendum: JDK 27+ and Native OpenJDK PQC Support

As quantum-resistant cryptography standards mature, OpenJDK is incorporating native PQC support directly into standard Java releases:
- Starting with **JDK 27**, standard JDK Security Providers (`SunJSSE`) include native support for NIST post-quantum key encapsulation standards (JEP / ML-KEM).
- **Google Cloud Java Client Libraries**: Google Cloud Java client SDKs use Conscrypt by default whenever it is available on the platform (delivering hardware-accelerated BoringSSL performance across all Java releases).
- **Your Own Applications**: For your own Java applications or non-Conscrypt HTTPS connections running on JDK 27 or later, standard OpenJDK Security Providers automatically negotiate ML-KEM PQC key exchange out-of-the-box—even without Conscrypt or JNI native dependencies.
- No code or configuration changes are required in Google Cloud Java client libraries when running on JDK 27+.
Loading