Radiator Server Documentation — v10.33.4
Table of Contents
  • tls
  • Parameters
  • Example: HTTPS Server
  • Example: RadSec Server (RADIUS over TLS)
  • Example: TACACS+ over TLS
  • Example: Mutual TLS (mTLS)
  • EAP-TLS handshake logging
  • Example JSON log records
  • See Also
  • Session resumption and CRL enforcement

tls

The tls clause configures Transport Layer Security (TLS) for server listeners. This configuration applies to all server types that support TLS:

  • HTTP servers - Enables HTTPS with HTTP/1.1 and HTTP/2 support
  • RADIUS servers - Enables RadSec (RADIUS over TLS, RFC 6614) on port 2083
  • TACACS+ servers - Enables TACACS+ over TLS

Parameters

ParameterDescriptionRequired
certificateServer certificate name (from certificates block)Yes
certificate_keyServer private key name (from certificates block)Yes
server_ca_certificateAdditional certificates to append to the presented server certificate chain, typically intermediatesNo
require_client_certificateWhether clients must present a certificateNo
client_ca_certificateCA certificate for validating client certificatesConditional
@verificationCustom certificate verification pipelineNo
min_protocol_versionMinimum TLS protocol version (tlsv12 for TLS 1.2, tlsv13 for TLS 1.3)No
max_protocol_versionMaximum TLS protocol version (tlsv12 for TLS 1.2, tlsv13 for TLS 1.3)No
tls12_session_id_resumptionEnables TLS 1.2 SessionID resumption (true or false)No
session_cache_sizeMaximum number of stateful TLS resumption cache entries shared by TLS 1.2 SessionID and TLS 1.3 stateful ticket resumptionNo
tls12_session_id_resumption_lifetimeMaximum lifetime for TLS 1.2 SessionID cache entries as a duration (for example 24h, 30m, or 0s)No
tls13_session_ticketsNumber of TLS 1.3 session tickets to send (0 to disable)No
tls13_session_ticket_lifetimeAdvertised TLS 1.3 ticket lifetime as a duration (for example 24h, 30m, or 0s); 0 disables resumption ticketsNo
keylog_filenameFile path for TLS key logging (for debugging with Wireshark)No

require_client_certificate defaults to true when omitted. Set require_client_certificate false; for one-way TLS listeners such as a normal HTTPS endpoint.

The client_ca_certificate parameter is required when require_client_certificate is set to true.

server_ca_certificate is optional. Use it when the certificate configured in certificate does not already contain the full chain that clients should receive from the server.

tls12_session_id_resumption controls TLS 1.2 SessionID based resumption. When omitted, it defaults to false for all TLS listeners. TLS 1.2 ticket resumption is always disabled.

session_cache_size sets the maximum number of stateful TLS resumption cache entries for the listener. The cache is shared by TLS 1.2 SessionID resumption and TLS 1.3 stateful ticket resumption. When omitted, Radiator stores up to 256 entries. Increase this value for high-volume TLS listeners when clients need a longer window to resume sessions. The value must be at least 1.

Each cached session stores TLS resumption state, negotiated protocol details, optional client certificate data, and optional application data. A typical entry without a client certificate uses a few hundred bytes plus cache overhead. Entries that include client certificate chains are larger. Set session_cache_size so that the maximum cache memory fits the listener's memory budget.

tls12_session_id_resumption_lifetime sets the maximum lifetime for TLS 1.2 SessionID cache entries. The value accepts standard duration units (for example 24h, 30m, 90s, or 0s). A bare number is interpreted as milliseconds. Positive sub-second values are rejected because TLS session lifetimes are stored in whole seconds. When omitted, TLS 1.2 SessionID entries use a 24-hour lifetime.

tls13_session_tickets controls TLS 1.3 session tickets only. When omitted, it defaults to 0, so TLS 1.3 session resumption is disabled unless the listener explicitly enables ticket issuance. TLS 1.3 early data (0-RTT) is always disabled irrespective of this setting.

tls13_session_ticket_lifetime sets the advertised ticket_lifetime value carried in each TLS 1.3 NewSessionTicket message. The value accepts standard duration units (for example 24h, 30m, 90s); a bare number is interpreted as milliseconds for consistency with other Radiator duration parameters. The TLS 1.3 ticket_lifetime field is expressed in whole seconds, so sub-second positive values (such as 100ms) are rejected at configuration load to avoid silently disabling resumption. Setting it to 0 (or 0s) disables resumption ticket issuance entirely, equivalent to tls13_session_tickets 0;. When the parameter is omitted, ticket issuance is disabled. A positive lifetime only has an effect when tls13_session_tickets is also set to a value greater than 0.

When a listener allows both TLS 1.2 and TLS 1.3, Radiator uses a conservative shared-cache policy. If either protocol has resumption disabled, Radiator disables the shared server-side resumption cache for the listener. This avoids advertising TLS 1.2 SessionIDs that the server will not resume. Use separate TLS 1.2-only and TLS 1.3-only listeners if you need independent resumption settings for each protocol version.

Example: HTTPS Server

certificates {
    x509 "SERVER_CERT" {
        filename "/var/lib/radiator/certs/server.pem";
    }
    key "SERVER_KEY" {
        filename "/var/lib/radiator/certs/server-key.pem";
    }
}

servers {
    http "HTTPS_SERVER" {
        listen {
            protocol tls;
            port 8443;
            ip 0.0.0.0;

            tls {
                certificate "SERVER_CERT";
                certificate_key "SERVER_KEY";
                require_client_certificate false;
            }
        }
    }
}

Example: RadSec Server (RADIUS over TLS)

RadSec typically requires mutual TLS (mTLS) where both server and client authenticate with certificates:

certificates {
    x509 "RADSEC_CERT" {
        filename "/var/lib/radiator/certs/radsec-server.pem";
    }
    key "RADSEC_KEY" {
        filename "/var/lib/radiator/certs/radsec-server-key.pem";
    }
    x509 "RADSEC_SERVER_CA" {
        filename "/var/lib/radiator/certs/radsec-ca.pem";
    }
    x509 "RADSEC_CLIENT_CA" {
        filename "/var/lib/radiator/certs/radsec-client-ca.pem";
    }
}

servers {
    radius "RADSEC" {
        listen {
            protocol tls;
            port 2083;
            ip 0.0.0.0;

            tls {
                certificate "RADSEC_CERT";
                certificate_key "RADSEC_KEY";
                server_ca_certificate "RADSEC_SERVER_CA";

                # RadSec requires client certificates
                require_client_certificate true;
                client_ca_certificate "RADSEC_CLIENT_CA";

                @verification {
                    if any {
                        cert.valid != true;
                        # Require certificate issued under network device policy
                        cert.policy != "1.3.6.1.4.1.99999.1.2.3";
                        # Require certificate from partner organization
                        cert.subject.o != "Partner Network Inc";
                    } then {
                        reject;
                    } else {
                        accept;
                    }
                }
            }
        }

        clients "RADSEC_CLIENTS";
    }
}

Example: TACACS+ over TLS

Add a tls { ... } block to a TACACS+ server listen { protocol tls; ... } section. The TLS listener honors ip-accept, listener timeout, keepalive, and per-client timeout exactly like the plain TCP listener.

servers {
    tacacs-plus "TACACS_TLS" {
        listen {
            protocol tls;
            port 300;
            ip 0.0.0.0;
            ip-accept "TACACS_TLS_ACCESS";
            timeout 30s;

            tls {
                certificate "TACACS_SERVER_CERT";
                certificate_key "TACACS_SERVER_KEY";
                require_client_certificate true;
                client_ca_certificate "TACACS_CLIENT_CA";
            }
        }

        clients "TACACS_TLS_CLIENTS";
        policy "POLICY_TACACS_PLUS";
    }
}

Notes:

  • TACACS+ TLS and RadSec listeners support proxy-protocol v2;. The proxy sends the PROXY header before the TLS handshake. Radiator reads the header first, then uses the real client address from it for client matching.
  • Prefer running TACACS+ TLS and TACACS+ TCP on separate ports (and ideally separate tacacs-plus server blocks). Distinct ports keep the configuration easier to reason about, simplify firewall rules, and avoid surprises when the same client address appears under both transports. If you must share the address space, TACACS+ clients can declare protocol tls; in their source block to disambiguate; see clients.tacacs-plus for the matching rules.
  • For TACACS+ over TLS deployment details, including listener, client, and obfuscation settings, see TACACS+ Authentication, Authorization, and Accounting.

For policy, multistage authentication, and operational guidance, see TACACS+ Authentication, Authorization, and Accounting.

Example: Mutual TLS (mTLS)

When client certificate verification is required:

certificates {
    x509 "SERVER_CERT" {
        filename "/var/lib/radiator/certs/server.pem";
    }
    key "SERVER_KEY" {
        filename "/var/lib/radiator/certs/server-key.pem";
    }
    x509 "SERVER_CA" {
        filename "/var/lib/radiator/certs/ca.pem";
    }
    x509 "CLIENT_CA" {
        filename "/var/lib/radiator/certs/client-ca.pem";
    }
}

servers {
    http "MTLS_SERVER" {
        listen {
            protocol tls;
            port 8443;
            ip 0.0.0.0;

            tls {
                certificate "SERVER_CERT";
                certificate_key "SERVER_KEY";
                server_ca_certificate "SERVER_CA";

                # Require and validate client certificates
                require_client_certificate true;
                client_ca_certificate "CLIENT_CA";
            }
        }
    }
}

EAP-TLS handshake logging

EAP-TLS and the EAP methods that tunnel TLS inside it (EAP-TTLS, EAP-PEAP, EAP-TEAP) emit a structured logging scope around the inner TLS handshake. The records below show example log entries. Fragment records do not include payload bytes; use a packet capture and keylog_filename for byte-level analysis in Wireshark.

Example JSON log records

A successful EAP-TLS handshake over TLS 1.3 (with --json-log-format):

{
  "timestamp": "2026-05-21T10:14:07.482914Z",
  "level": "DEBUG",
  "namespace": ["server", "radius", "AUTH_RADIUS_UDP"],
  "message": "TLS handshake complete",
  "fields": {
    "context_id": "e7c1d2c6-4a3f-4f9c-8f9a-2d4f1b1c9a44",
    "eap_type": "tls",
    "eap_identifier": 12,
    "eaptls.version": 0,
    "tls.role": "server",
    "tls.timeout_ms": 5000,
    "tls.max_fragment_size": 1024,
    "tls.version": "TLSv1_3",
    "tls.ciphersuite": "TLS13_AES_256_GCM_SHA384",
    "tls.key_exchange_group": "X25519",
    "tls.session_resumed": false,
    "tls.exporter.label": "EXPORTER_EAP_TLS_Key_Material",
    "tls.msk.exported": true,
    "tls.msk.len": 128,
    "tls.eap_tls13_trailer": true,
    "tls.peer_cert.subject": "cn=testUser,o=Radiator Software,c=FI",
    "tls.peer_cert.issuer": "cn=Radiator Intermediate CA I2,o=Radiator Software,c=FI",
    "tls.peer_cert.chain_len": 2,
    "tls.peer_cert.serial": "1a:2b:3c",
    "tls.peer_cert.not_before": 1716285247,
    "tls.peer_cert.not_before_timestamp": "2024-05-21T09:54:07Z",
    "tls.peer_cert.not_after": 1747821247,
    "tls.peer_cert.not_after_timestamp": "2025-05-21T09:54:07Z",
    "tls.peer_cert.fingerprint_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "tls.peer_cert.sans": "dns:testuser.radiatorsoftware.example.com",
    "tls.peer_cert.authority_key_identifier": "5c8fb3d99eabd69c6f884fa4aab442b5292f2f6b",
    "tls.peer_cert.subject_key_identifier": "9d2892c2c6730bd7ee8b069d115ffe5e77d1dc7f",
    "tls.peer_cert.intermediates": [
      {
        "chain_index": 1,
        "subject": "cn=Radiator Intermediate CA I2,o=Radiator Software,c=FI",
        "issuer": "cn=Radiator Root CA,o=Radiator Software,c=FI",
        "serial": "10:02",
        "not_before": 1704067200,
        "not_before_timestamp": "2024-01-01T00:00:00Z",
        "not_after": 1861833600,
        "not_after_timestamp": "2028-12-31T00:00:00Z",
        "fingerprint_sha256": "cfec366a0526a404cfe154527822b93fb9a8cdfbabf6fc259c0b24ea0ff8176e",
        "authority_key_identifier": "884a0c7f8a3f38d8c2e886c83276f6d0a3b5cc37",
        "subject_key_identifier": "5c8fb3d99eabd69c6f884fa4aab442b5292f2f6b"
      }
    ],
    "identity": "testUser@radiatorsoftware.example.com",
    "calling_station_id": "22-44-66-00-11-22",
    "called_station_id": "22-44-66-11-22-33:test.radiator",
    "nas_identifier": "ap-lobby-1",
    "nas_port": 0,
    "nas_ip_address": "192.0.2.10"
  }
}

A handshake failure where the Windows supplicant rejected the server certificate or certificate chain. Depending on the Windows version and certificate problem, the alert can appear as AccessDenied, InternalError, or another fatal TLS alert:

{
  "timestamp": "2026-05-21T10:15:21.107834Z",
  "level": "WARN",
  "namespace": ["server", "radius", "AUTH_RADIUS_UDP"],
  "message": "TLS handshake failed",
  "fields": {
    "context_id": "1f8d3b4a-3b9d-49a1-b2a4-8a3f4b6c8d10",
    "eap_type": "ttls",
    "eap_identifier": 4,
    "tls.role": "server",
    "tls.timeout_ms": 5000,
    "tls.max_fragment_size": 1024,
    "identity": "anonymous@radiatorsoftware.example.com",
    "calling_station_id": "AA-BB-CC-11-22-33",
    "called_station_id": "11-22-33-AA-BB-CC:corp-wifi",
    "nas_identifier": "ap-floor3-east",
    "handshake.error.source": "tls",
    "handshake.error.kind": "alert_received",
    "handshake.error.detail": "received fatal alert: AccessDenied"
  }
}

An outbound fragment record produced at Trace level when max-fragment-size forces the server certificate flight to be split across several EAP-TLS fragments:

{
  "timestamp": "2026-05-21T10:14:07.481102Z",
  "level": "TRACE",
  "namespace": ["server", "radius", "AUTH_RADIUS_UDP"],
  "message": "EAP-TLS fragment sent to peer",
  "fields": {
    "context_id": "e7c1d2c6-4a3f-4f9c-8f9a-2d4f1b1c9a44",
    "eap_type": "tls",
    "eap_identifier": 3,
    "tls.role": "server",
    "tls.max_fragment_size": 256,
    "tls.bytes_total": 2104,
    "frag.index": 1,
    "frag.size": 252,
    "frag.remaining": 1852,
    "frag.more": true,
    "frag.length_included": true
  }
}

See Also

Session resumption and CRL enforcement

Resumed TLS sessions skip the certificate verification callback, so a peer whose certificate has been revoked since the original handshake can continue using a resumption ticket or session ID until that ticket expires. When prompt revocation enforcement is required (for example mTLS deployments that rely on crl or crl-directory), disable TLS 1.3 session tickets so every connection performs a full handshake:

tls {
    certificate "SERVER_CERT";
    certificate_key "SERVER_KEY";
    server_ca_certificate "CA_CERT";

    # Force a full handshake on every connection so the current CRL
    # snapshot is consulted for every peer.
    tls12_session_id_resumption false;
    tls13_session_tickets 0;
}

TLS 1.2 SessionID resumption and TLS 1.3 session tickets are disabled by default for all TLS listeners. Set tls12_session_id_resumption true; or tls13_session_tickets N; only on listeners that should allow resumption.

Navigation
  • @init

  • @verification

  • aaa

  • backends

  • caches

  • captures

  • certificates

  • clients

  • conditions

  • dictionary

  • hmac-otp

  • include

  • interval

  • ip-accept

  • license

  • logging

  • management

  • proxy-protocol

  • scripts

  • servers

    • buffer

    • clients

    • http

    • ip

    • keepalive

    • policy

    • port

    • pre-client

    • protocol

    • radius

    • timeout

    • tls

  • statistics

  • stats

  • timer

  • ui