Google Cloud
Is PQC enabled? — quick check
macOS / Linux
# 1) No-dependency check — identify this machine first.
uname -a 2>/dev/null || true
# 2) Dependency check — prompt before installing anything.
if ! command -v openssl >/dev/null 2>&1; then
echo 'OpenSSL was not found. A local PQC proof needs OpenSSL 3.5+.'
printf 'Install OpenSSL now? [y/N] '
read answer
case "$answer" in
[Yy]*)
if command -v brew >/dev/null 2>&1; then brew install openssl@3
elif command -v apt-get >/dev/null 2>&1; then sudo apt-get update && sudo apt-get install -y openssl
elif command -v dnf >/dev/null 2>&1; then sudo dnf install -y openssl
elif command -v yum >/dev/null 2>&1; then sudo yum install -y openssl
else echo 'No supported package manager found. Install OpenSSL 3.5+ and retry.'; exit 1
fi ;;
*) echo 'Install OpenSSL 3.5+ and retry for a local PQC proof.'; exit 1 ;;
esac
fi
OPENSSL=openssl
if command -v brew >/dev/null 2>&1; then
BREW_OPENSSL="$(brew --prefix openssl@3 2>/dev/null)/bin/openssl"
[ -x "$BREW_OPENSSL" ] && OPENSSL="$BREW_OPENSSL"
fi
$OPENSSL version
if ! $OPENSSL list -tls-groups 2>/dev/null | grep -qiE 'X25519MLKEM768|MLKEM|Kyber'; then
echo 'This OpenSSL does not advertise ML-KEM groups. Upgrade to OpenSSL 3.5+ or load oqsprovider, then retry.'
exit 1
fi
$OPENSSL list -kem-algorithms 2>/dev/null | grep -iE 'mlkem|kyber' || echo 'no native ML-KEM (try "$OPENSSL list -providers" for oqsprovider)'
# 3) Live handshake against your server. The 'Negotiated TLS1.3 group' line
# (or 'Server Temp Key' on OpenSSL 3.5) tells you what was negotiated
# end-to-end — no external service required.
$OPENSSL s_client -connect example.com:443 -tls1_3 -groups X25519MLKEM768 </dev/null 2>&1 |
grep -E 'Negotiated TLS1\.3 group|Server Temp Key|Cipher is|alert' Expected when PQC is ON
OpenSSL 3.6.2 7 Apr 2026
X25519MLKEM768 @ default
Negotiated TLS1.3 group: X25519MLKEM768
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 What you'll see when PQC is OFF
OpenSSL 3.0.13 30 Jan 2024
no native ML-KEM
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server Temp Key: X25519, 253 bits To enable PQ on your server, see the nginx, Apache, or Caddy KB pages — it's one line: ssl_ecdh_curve / SSLOpenSSLConfCmd Groups / tls.curve_preferences = X25519MLKEM768:X25519:secp384r1.
Windows PowerShell
# 1) No-dependency check — identify this machine first.
[System.Environment]::OSVersion.Version
Get-ComputerInfo | Select-Object OsName,OsVersion,OsBuildNumber
# 2) Dependency check — prompt before installing anything.
function Confirm-Install($Message) {
$answer = Read-Host "$Message Install now? [y/N]"
return ($answer -match '^[Yy]')
}
function Get-OpenSSLPath {
$cmd = Get-Command openssl.exe -ErrorAction SilentlyContinue
if ($cmd) { return $cmd.Source }
$programFilesX86 = [Environment]::GetEnvironmentVariable('ProgramFiles(x86)')
$currentPath = (Get-Location).Path
$candidateDirs = @(
$(if ($env:ProgramFiles) { Join-Path (Join-Path $env:ProgramFiles 'OpenSSL-Win64') 'bin' }),
$(if ($programFilesX86) { Join-Path (Join-Path $programFilesX86 'OpenSSL-Win32') 'bin' }),
$(if ($env:LOCALAPPDATA) { Join-Path (Join-Path (Join-Path $env:LOCALAPPDATA 'Programs') 'OpenSSL-Win64') 'bin' }),
$currentPath,
$(if ($currentPath) { Join-Path (Join-Path $currentPath 'openssl') 'bin' })
)
foreach ($dir in $candidateDirs) {
if (-not $dir) { continue }
$candidate = Join-Path $dir 'openssl.exe'
if ($candidate -and (Test-Path -LiteralPath $candidate -PathType Leaf)) { return $candidate }
}
return $null
}
$openssl = Get-OpenSSLPath
if (-not $openssl) {
Write-Warning 'OpenSSL 3.5+ was not found. Built-in Windows PowerShell/Schannel cannot prove the PQC named group.'
if ((Get-Command winget -ErrorAction SilentlyContinue) -and (Confirm-Install 'Install ShiningLight OpenSSL with winget?')) {
winget install ShiningLight.OpenSSL.Light
$openssl = Get-OpenSSLPath
}
if (-not $openssl) { 'Install or pre-stage OpenSSL 3.5+ and retry.'; return }
}
& $openssl version
$groups = (& $openssl list -tls-groups 2>$null) -join [Environment]::NewLine
if ($groups -notmatch 'X25519MLKEM768|MLKEM|Kyber') {
'Local OpenSSL does not advertise ML-KEM groups. Install or pre-stage OpenSSL 3.5+ and retry.'
return
}
& $openssl list -kem-algorithms | Select-String -Pattern 'mlkem|kyber'
# 3) Live handshake — fully local, no api.checkpqc.app needed.
& $openssl s_client -connect example.com:443 -tls1_3 -groups X25519MLKEM768 2>&1 |
Select-String -Pattern 'Negotiated TLS1\.3 group|Server Temp Key|Cipher is|alert' Expected when PQC is ON
OpenSSL 3.6.2 7 Apr 2026
X25519MLKEM768 @ default
Negotiated TLS1.3 group: X25519MLKEM768
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 What you'll see when PQC is OFF
OpenSSL 1.1.1w 11 Sep 2023
# (no mlkem line)
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# (no group line — 1.1.1 cannot offer ML-KEM) Schannel cannot expose the negotiated TLS named group programmatically, so a local OpenSSL binary is the most reliable offline answer on Windows.
HTTPS Load Balancer
Google enabled X25519Kyber768 on the External HTTPS Load Balancer in 2023 and
migrated to the standardized X25519MLKEM768 in 2024. Capable clients negotiate
hybrid PQC automatically — there is no toggle to flip.
Use a modern SSL policy:
gcloud compute ssl-policies create modern-tls13 \
--profile MODERN \
--min-tls-version 1.2 Attach it to the target HTTPS proxy.
Cloud CDN
Inherits the HTTPS LB TLS stack. Same hybrid PQC behavior.
App Engine, Cloud Run, Cloud Functions
Front-ended by Google Front Ends (GFE) which negotiate hybrid PQC with capable clients. No customer configuration.
Verify
if ! command -v openssl >/dev/null 2>&1; then
echo 'OpenSSL was not found.'
printf 'Install OpenSSL now? [y/N] '; read answer
case "$answer" in [Yy]*) sudo apt-get update && sudo apt-get install -y openssl ;; *) exit 1 ;; esac
fi
openssl s_client -connect www.google.com:443 -tls1_3 \
-groups X25519MLKEM768 </dev/null 2>&1 | grep "Cipher is\|alert" Background
Google Cloud's HTTPS load balancer terminates TLS at the same edge that fronts
google.com. Google deployed X25519Kyber768 at the edge in 2023 and
transitioned to X25519MLKEM768 alongside Chrome's stable rollout. The
Cloud HTTPS LB inherits this; no per-backend toggle exists.
Status by service
- Global / regional external HTTPS LB — hybrid PQ active.
- Cloud Run / Cloud Functions custom domains — fronted by HTTPS LB when behind a load balancer; verify per hostname with the probe.
- Cloud CDN — same edge, same PQ posture.
- Internal HTTPS LB — controlled by the SSL policy attached; choose
a profile of
MODERNorRESTRICTEDfor TLS 1.3.
SSL policies
Hybrid groups are negotiated when both ends advertise them; GCP's SSL policy controls protocol versions and cipher suites, not named groups directly.