← Knowledge base

Azure

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.

Front Door

Azure Front Door supports TLS 1.3 on Standard and Premium tiers. As of 2026 Microsoft has not exposed a customer-facing toggle for hybrid post-quantum key agreement on Front Door endpoints. Track the Azure updates feed and the Front Door docs for the rollout.

Application Gateway

Application Gateway v2 supports TLS 1.3 via SSL Policy. PQC groups are not yet configurable. If you need hybrid PQC today, terminate TLS on a backend you control (nginx, Caddy, or Apache with oqsprovider) and run AGW in TCP-only mode upstream.

Azure CDN (Front Door classic)

Same status — TLS 1.3 yes, PQC no.

What you can do today

Background

Azure terminates HTTPS at several front doors: Azure Front Door, Application Gateway, API Management, and the per-service ingress on App Service / Functions / Container Apps. Underneath, Microsoft is rolling out PQ TLS via the SymCrypt library, the same crypto core that powers Schannel.

Status by service (early 2026)

References

Run the check on your site →