---
title: 'Tutorial: Enable Quantum-Resistant Encryption in Access Server with Post-Quantum Cryptography (PQC)'
canonical: https://openvpn.net/as-docs/v3/tutorials/tutorial--post-quantum-cryptography/
product: Access Server Docs
description: Enable post-quantum cryptography (PQC) in OpenVPN Access Server to protect VPN tunnels against future quantum computer attacks — covers configuring X25519MLKEM768 via tls-groups, FIPS-compatible algorithms (SecP256r1MLKEM768), client requirements, and verifying PQC key agreement in logs.
---

# Tutorial: Enable Quantum-Resistant Encryption in Access Server with Post-Quantum Cryptography (PQC)

## Overview

Post-Quantum Cryptography (PQC) provides quantum-resistant, or quantum-safe, cryptographic algorithms designed to withstand attacks from sufficiently powerful quantum computers.

A future quantum computer could potentially break widely used public-key cryptography based on RSA and elliptic curves using Shor's algorithm. This also creates a present-day harvest-now, decrypt-later risk, where an attacker records encrypted traffic now with the intent of decrypting it in the future when sufficiently capable quantum computing becomes available.

Access Server can use post-quantum key agreement for VPN connections when both the server and VPN client support it. With OpenSSL 3.5 or newer, the default post-quantum group is X25519MLKEM768, which combines the classical X25519 elliptic curve with ML-KEM (MLKEM), the NIST-standardized post-quantum key encapsulation mechanism.

In most supported configurations, Access Server and the VPN client can negotiate PQC automatically. This tutorial shows you how to:

- Verify that your environment supports PQC.
- Force post-quantum key agreement using the `tls-groups` directive.
- Maintain compatibility with clients that don't yet support PQC.
- Verify the negotiated key agreement in Access Server and client logs.
- Configure PQC when Access Server is running in FIPS mode.

> **Tip**
>
> Post-quantum cryptography is also becoming increasingly relevant to zero trust and security requirements in regulated environments. For related architecture guidance, see [Zero Trust Network Access](https://openvpn.net/use-cases/zero-trust-network-access/).

## Prerequisites

Before you begin, ensure you have:

- Access Server installed on a Linux host with OpenSSL 3.5 or newer.

  At the time of this writing, supported Linux distributions with OpenSSL 3.5 or newer include:
  - Ubuntu 26.04 LTS
  - Debian 13
  - RHEL 9 and compatible distributions
  - RHEL 10 and compatible distributions
- An OpenVPN client that uses OpenSSL 3.5 or newer.

  At the time of this writing, OpenVPN Connect v3 doesn't support OpenSSL 3.5. You can instead use a compatible OpenVPN Community client, such as:
  - [OpenVPN GUI for Windows](https://openvpn.net/community/)
  - [Tunnelblick for macOS](https://tunnelblick.net/)
  - [OpenVPN 2 for Linux from the appropriate distribution software repository](https://community.openvpn.net/Pages/OpenVPN%20software%20repos)

    > **Important**
    >
    > When using OpenVPN 2 on Linux, add the following directive to the connection profile so the client requests PQC:
    >
    > ```
    > tls-groups "X25519MLKEM768"
    > ```
    >
    > This additional profile configuration isn't required for OpenVPN GUI for Windows or Tunnelblick for macOS.
- Admin Web UI access or console access with root privileges.
- One or more users configured in Access Server.

> **Note**
>
> In our documentation, we use example IPv4 addresses and subnets [reserved for documentation](https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv4), such as `192.0.2.0/24`, `198.51.100.0/24`, and `203.0.113.0/24`.
>
> Ensure you replace them with valid IPv4 addresses and subnets for your network(s).

## Before you begin

If both Access Server and the VPN client use OpenSSL 3.5 or newer, they can negotiate post-quantum key agreement without forcing a specific group. The configuration in this tutorial is primarily useful when you need to **require** PQC or explicitly control which TLS groups are permitted.

Test these changes in a non-production environment before deploying them to users.

### Understand client compatibility before forcing PQC

If you configure Access Server to allow **only** a post-quantum group such as `X25519MLKEM768`, clients that don't support that group won't be able to connect.

An unsupported connection can fail with an OpenSSL error similar to: `OpenSSL: error:0A000065:SSL routines::no suitable key share:`

For example, if your users currently connect with OpenVPN Connect v3, forcing `X25519MLKEM768` would prevent those clients from connecting.

To support both PQC-capable clients and clients that use traditional elliptic curve groups, configure both groups:

```
tls-groups "X25519MLKEM768:X25519"
```

Plan your migration accordingly before requiring PQC across a production deployment.

### FIPS mode considerations

Access Server running in FIPS mode supports the following post-quantum groups:

- `SecP256r1MLKEM768`
- `SecP384r1MLKEM1024`

If you're using FIPS mode, see:

- [FIPS Compliance in Access Server](https://openvpn.net/as-docs/fips-compliance.md)
- [Tutorial: Enable FIPS Mode on Ubuntu and RHEL for Access Server](https://openvpn.net/as-docs/v3/tutorials/tutorial--enable-fips-mode-ubuntu-rhel.md)

## Step 1: Configure Access Server to require PQC

Access Server and supported clients use `X25519MLKEM768` for post-quantum key agreement by default. Use the `tls-groups` directive when you want to explicitly require this group.

You can configure it from the Admin Web UI or command line.

### Admin Web UI

1. Sign in to the Admin Web UI.
2. Navigate to **Advanced → OpenVPN Directives**.
3. Under **Server config directives**, enter:

   ```
   tls-groups X25519MLKEM768
   ```

   This allows only `X25519MLKEM768`, so clients that don't support this post-quantum group can't connect.
4. To allow PQC-capable clients while maintaining compatibility with clients that support X25519, use this instead:

   ```
   tls-groups "X25519MLKEM768:X25519"
   ```
5. Select **Save** and **Restart**.

### Command line

1. Connect to the console and get root privileges.
2. To require `X25519MLKEM768`, run:

   ```
   sacli --key "vpn.server.config_text" --value "tls-groups X25519MLKEM768" ConfigPut
   ```
3. To allow both `X25519MLKEM768` and X25519 for compatibility with clients that don't support PQC, use:

   ```
   sacli --key "vpn.server.config_text" --value "tls-groups \"X25519MLKEM768:X25519\"" ConfigPut
   ```
4. Restart Access Server services:

   ```
   sacli start
   ```

## Step 2: Connect and verify the post-quantum key agreement

Download a connection profile and connect to Access Server with a supported client. After the VPN connection succeeds, verify that the connection negotiated `X25519MLKEM768`.

### Verify from Access Server

1. Connect to the console and get root privileges.
2. Search the Access Server log for the negotiated key agreement:

   ```
   grep "key agreement" /var/log/openvpnas.log
   ```

   - Example output:

     ```
     [stdout#info] [OVPN 3] OUT: '2026-08-24 14:39:27 udp4:203.0.113.55:51371 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, peer certificate: 384 bits ECsecp384r1, signature: ecdsa-with-SHA256, peer temporary key: 768 bits X25519MLKEM768, peer signing digest/type: ecdsa_secp384r1_sha384 ECDSA, key agreement: X25519MLKEM768'
     ```
3. Confirm that the output contains:

   ```
   key agreement: X25519MLKEM768
   ```

### Verify from the VPN client

1. Open the VPN client logs and locate the control-channel details.
   - Example:

     ```
     Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, peer certificate: 384 bits ECsecp384r1, signature: ecdsa-with-SHA256, peer signing digest/type: ecdsa_secp384r1_sha384 ECDSA, key agreement: X25519MLKEM768
     ```
2. Confirm that the log contains:

   ```
   key agreement: X25519MLKEM768
   ```

## Optional: Configure a different ML-KEM group

Use this configuration when you need `SecP256r1MLKEM768` or `SecP384r1MLKEM1024` instead of `X25519MLKEM768`.

> **Tip**
>
> If Access Server is running in FIPS mode, use one of these supported groups.

Ensure you configure the selected group on both Access Server and the VPN client. The examples below use `SecP256r1MLKEM768`. You can substitute `SecP384r1MLKEM1024` where appropriate.

### Step 1: Configure Access Server

You an set this up from the Admin Web UI or command line.

#### Admin Web UI

1. Sign in to the Admin Web UI.
2. Navigate to **Advanced → OpenVPN Directives**.
3. Under **Server config directives**, enter:

   ```
   tls-groups SecP256r1MLKEM768
   ```
4. To allow PQC while maintaining compatibility with clients using `secp256r1`, configure:

   ```
   tls-groups "SecP256r1MLKEM768:secp256r1"
   ```
5. Select **Save** and **Restart**.

#### Command line

1. Connect to the console and get root priviliges.
2. To require `SecP256r1MLKEM768`, run:

   ```
   sacli --key "vpn.server.config_text" --value "tls-groups SecP256r1MLKEM768" ConfigPut
   ```
3. To allow both the post-quantum group and `secp256r1`, run:

   ```
   sacli --key "vpn.server.config_text" --value "tls-groups \"SecP256r1MLKEM768:secp256r1\"" ConfigPut
   ```
4. Restart Access Server services:

   ```
   sacli start
   ```

### Step 2: Configure the VPN client

1. Download a new connection profile (`.ovpn` file).
2. Open the connection profile in a text editor.
3. Add:

   ```
   tls-groups SecP256r1MLKEM768
   ```
4. To allow both the post-quantum group and `secp256r1`, use:

   ```
   tls-groups "SecP256r1MLKEM768:secp256r1"
   ```
5. Save the connection profile.

### Step 3: Connect and verify the key agreement

1. Connect using the modified connection profile.
2. Connect to the Access Server console and get root privileges.
3. Check the Access Server logs for the key agreement line:

   ```
   grep "key agreement" /var/log/openvpnas.log
   ```

   - Example output:

     ```
     [stdout#info] [OVPN 3] OUT: '2026-08-24 14:39:27 udp4:203.0.113.55:51371 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, peer certificate: 384 bits ECsecp384r1, signature: ecdsa-with-SHA256, peer temporary key: 768 bits X25519MLKEM768, peer signing digest/type: ecdsa_secp384r1_sha384 ECDSA, key agreement: SecP256r1MLKEM768'
     ```
4. Confirm that the log contains:

   ```
   key agreement: SecP256r1MLKEM768
   ```
5. Verify the same value in the VPN client log:

   ```
   Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, peer certificate: 384 bits ECsecp384r1, signature: ecdsa-with-SHA256, peer signing digest/type: ecdsa_secp384r1_sha384 ECDSA, key agreement: SecP256r1MLKEM768
   ```

## Related resources

- [FIPS Compliance in Access Server](https://openvpn.net/as-docs/fips-compliance.md)
- [Tutorial: Enable FIPS Mode on Ubuntu and RHEL for Access Server](https://openvpn.net/as-docs/v3/tutorials/tutorial--enable-fips-mode-ubuntu-rhel.md)
- [Security & Certificates tutorials](https://openvpn.net/as-docs/v3/tutorials/security---certificates.md)
- [Tutorial: Install, Verify, and Troubleshoot OpenVPN DCO in Access Server](https://openvpn.net/as-docs/v3/tutorials/tutorial--turn-on-openvpn-dco.md)

---

Prev: [Encryption and TLS Settings](https://openvpn.net/as-docs/v3/tutorials/encryption-and-tls-settings.md)
Next: [Tutorial: Change the Data-Channel Encryption Cipher](https://openvpn.net/as-docs/v3/tutorials/tutorial--change-encryption-cipher.md)
Index: https://openvpn.net/as-docs/llms.txt
