EAP-TLS

EAP-TLS certificate-based authentication for 802.1X network access control.

Certificate Requirements

EAP-TLS is mutual authentication: both client and server present certificates. Every certificate in the chain must meet specific extension requirements or authentication silently fails.

Server Certificate (ISE/RADIUS)

extendedKeyUsage = serverAuth
subjectAltName = DNS:<ise-fqdn>

The ISE RADIUS certificate MUST have serverAuth EKU. The client validates the server’s identity before sending its own certificate. Without this, the supplicant rejects the RADIUS server.

Client Certificate (Workstation)

extendedKeyUsage = clientAuth
subjectAltName = DNS:<hostname>.inside.domusdigitalis.dev

The client certificate MUST have clientAuth EKU. ISE validates this before granting network access.

CA Chain

Both sides must trust the CA chain. The root CA (or intermediate) must be installed in:

  • ISE: Administration > System > Certificates > Trusted Certificates

  • Client: System trust store (/etc/ssl/certs/ on Linux, certmgr on Windows)

wpa_supplicant Configuration

EAP-TLS wpa_supplicant.conf — the working config
network={
    ssid="Corp-Wireless"
    key_mgmt=WPA-EAP
    eap=TLS
    identity="evan@inside.domusdigitalis.dev"
    ca_cert="/etc/ssl/certs/domus-ca-chain.pem"
    client_cert="/etc/ssl/certs/client.pem"
    private_key="/etc/ssl/private/client.key"
    private_key_passwd="<REDACTED>"
    phase1="tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1"
}
Wired 802.1X — same config, different transport
network={
    key_mgmt=IEEE8021X
    eap=TLS
    identity="evan@inside.domusdigitalis.dev"
    ca_cert="/etc/ssl/certs/domus-ca-chain.pem"
    client_cert="/etc/ssl/certs/client.pem"
    private_key="/etc/ssl/private/client.key"
    private_key_passwd="<REDACTED>"
}
Start wpa_supplicant for wired 802.1X
sudo wpa_supplicant -i enp0s31f6 -c /etc/wpa_supplicant/wpa_supplicant-wired.conf -D wired

eapol_test — Testing Without the Network

eapol_test is the single most useful tool for debugging EAP-TLS. It speaks RADIUS directly, bypassing the switch/AP entirely.

Install eapol_test (from wpa_supplicant source)
# Arch: included in wpa_supplicant package
# Ubuntu: build from source with CONFIG_EAPOL_TEST=y
Create eapol_test config
network={
    eap=TLS
    identity="evan@inside.domusdigitalis.dev"
    ca_cert="/etc/ssl/certs/domus-ca-chain.pem"
    client_cert="/etc/ssl/certs/client.pem"
    private_key="/etc/ssl/private/client.key"
    private_key_passwd="<REDACTED>"
}
Run eapol_test against ISE
eapol_test -c /tmp/eapol-test.conf -a 10.50.1.20 -p 1812 -s <REDACTED> -r 1
Interpret the output — the only two lines that matter
SUCCESS                    # Authentication passed
FAILURE                    # Authentication failed — check ISE live logs
Verbose output for debugging — shows TLS handshake details
eapol_test -c /tmp/eapol-test.conf -a 10.50.1.20 -p 1812 -s <REDACTED> -r 1 2>&1 | \
    grep -E "TLS|EAP|RADIUS|certificate|verify"

ISE Certificate Store

Verify ISE trusted certificates via API (ERS)
curl -sk -u admin:<REDACTED> \
    https://10.50.1.20:9060/ers/config/systemcertificate | \
    python3 -m json.tool

ISE Certificate Checklist

Location Certificate Purpose

Trusted Certificates

Root CA

Validates client certificates

Trusted Certificates

Intermediate CA

Completes the chain

System Certificates

RADIUS/EAP certificate

Server-side TLS in EAP-TLS handshake

System Certificates

Admin certificate

Web UI HTTPS

Certificate Chain Validation

Verify the client cert chains to the CA — do this before deploying
openssl verify -CAfile /etc/ssl/certs/domus-ca-chain.pem /etc/ssl/certs/client.pem
Verify the server cert (ISE RADIUS cert) chains correctly
openssl s_client -connect 10.50.1.20:443 -showcerts </dev/null 2>/dev/null | \
    openssl x509 -noout -subject -issuer -dates -ext subjectAltName,extendedKeyUsage
Check EKU on a certificate — must match expected role
openssl x509 -in client.pem -noout -ext extendedKeyUsage
# Expected: TLS Web Client Authentication

openssl x509 -in ise-radius.pem -noout -ext extendedKeyUsage
# Expected: TLS Web Server Authentication
Check SAN — hostname must appear here, not just CN
openssl x509 -in client.pem -noout -ext subjectAltName

Common Failure Modes

Client Cert Rejected by ISE

Symptom: ISE live log shows "certificate unknown" or "bad certificate"
Cause 1: Client cert EKU missing clientAuth
Cause 2: CA not in ISE Trusted Certificates store
Cause 3: Client cert expired
Cause 4: CRL check enabled but CRL unreachable
Diagnose: check the certificate against all four causes
openssl x509 -in client.pem -noout -dates -ext extendedKeyUsage,authorityInfoAccess

Supplicant Rejects RADIUS Server

Symptom: wpa_supplicant logs "server certificate verify failed"
Cause 1: CA chain file doesn't include the intermediate
Cause 2: ISE RADIUS cert has wrong SAN (hostname mismatch)
Cause 3: ISE RADIUS cert expired
Cause 4: ca_cert path in wpa_supplicant.conf is wrong
Diagnose: connect to ISE RADIUS port and inspect the cert
openssl s_client -connect 10.50.1.20:1812 </dev/null 2>/dev/null | \
    openssl x509 -noout -subject -issuer -dates -ext subjectAltName

TLS Version Mismatch

Symptom: handshake failure, no further detail
Cause: Client enforces TLS 1.2+ but server offers TLS 1.0 only
Fix: Update ISE TLS configuration or adjust phase1 in supplicant

NPS vs ISE Differences

Feature Microsoft NPS Cisco ISE

Certificate store

Windows Certificate MMC

ISE Admin > Certificates

EAP types

PEAP, EAP-TLS

PEAP, EAP-TLS, EAP-FAST, TEAP

Certificate matching

CN or SAN

SAN preferred, CN fallback

CRL checking

Via LDAP/HTTP CDP

Built-in + external CDP

Client cert source

AD auto-enrollment

Manual, Vault, or SCEP

Policy engine

Network Policy conditions

Policy Sets with conditions + results

Logging

Event Viewer

Live Logs + Reports (much better)

RADIUS CoA

Limited

Full support (CoA, port bounce, re-auth)