How to check cipher suites of a server
Offer one family at a time and read what comes back: openssl s_client -connect example.com:443 -servername example.com -tls1_2 -cipher 'kRSA@SECLEVEL=0' </dev/null 2>&1. A Cipher : line names a suite the server accepted. An SSL alert number 40 line means the server declined that whole family.
Why check this
The negotiated suite tells you what one client got. The accepted set tells you what the weakest client can get, and that is the number a security review asks for. Run this after a TLS profile change and before a release that adds a payment or health data path. A concrete failure it prevents: an origin left with RSA key exchange enabled, so a recorded session can be decrypted later by anyone who obtains the private key, while every browser test looked clean because browsers pick the strong suite.
OpenSSL has no single command that enumerates a remote server's list. The protocol never publishes it. The ServerHello names one suite, the one chosen for this connection, so the only way to learn the rest is to narrow your own offer and repeat the handshake. That is what the probes below do, and it is also why a full enumeration costs one connection per suite and belongs on infrastructure you own.
Rank what you find in this order. Suites with ECDHE provide forward secrecy, so a stolen private key cannot decrypt recorded traffic. Suites ending in GCM, POLY1305 or any TLS 1.3 name are AEAD, which removes the padding oracle class of attack that CBC suites carry. A suite with neither property is the finding worth writing up.
Prerequisites
- OpenSSL 1.1.1 or later.
openssl versionmust report it. The cipher name grammar is in the ciphers manual. - Your own build's cipher list limits every probe. A family your OpenSSL lacks cannot be offered at all.
- A shell with a
forloop. The loop in step 3 opens one connection per family, four in total.
Steps
- Step 1.
List what your client can offer for TLS 1.3. These three suites are the whole TLS 1.3 set.
openssl ciphers -v -s -tls1_3TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEADKx=anyandAu=anyare the TLS 1.3 change: key exchange and authentication left the suite name. - Step 2.
Read the suite the server picks when you offer everything.
openssl s_client -connect www.cloudflare.com:443 -servername www.cloudflare.com -tls1_2 </dev/null 2>/dev/null | grep 'Cipher :'Cipher : ECDHE-ECDSA-CHACHA20-POLY1305Read the suite from this indented
Cipher :line inside the session block, not from theNew,summary line above it. - Step 3.
Probe the four families that decide the verdict, one connection each.
for fam in "ECDHE+AESGCM" "ECDHE+SHA" "kRSA" "aNULL"; do if openssl s_client -connect www.cloudflare.com:443 -servername www.cloudflare.com -tls1_2 -cipher "$fam@SECLEVEL=0" </dev/null >/dev/null 2>&1; then echo "$fam: accepted"; else echo "$fam: refused"; fi; doneECDHE+AESGCM: accepted ECDHE+SHA: accepted kRSA: accepted aNULL: refusedkRSA: acceptedis the finding. That family has no forward secrecy. The suite negotiated there wasAES128-GCM-SHA256. - Step 4.
Find out who decides the order. Offer two suites, then offer the same two reversed.
for c in "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305" "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256"; do openssl s_client -connect www.cloudflare.com:443 -servername www.cloudflare.com -tls1_2 -cipher "$c" </dev/null 2>/dev/null | grep 'Cipher :'; doneCipher : ECDHE-ECDSA-AES128-GCM-SHA256 Cipher : ECDHE-ECDSA-CHACHA20-POLY1305The answer followed the order sent, so this server does not enforce its own preference between these two.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| Cipher : ECDHE-...-GCM or TLS_AES_... | Forward secrecy and an AEAD cipher | Pass. Record the name in the release notes. |
| Cipher : AES128-GCM-SHA256 with no ECDHE | RSA key exchange, no forward secrecy | Raise it. One leaked private key exposes every recorded session. |
| Cipher : ...-SHA or ...-SHA256 on a CBC suite | CBC with HMAC, not AEAD | Acceptable in TLS 1.2, first candidate for removal. |
| SSL alert number 40 | The server shares no suite in that family | The family is off. This is the result you want for aNULL. |
| no cipher match with no alert number | Your OpenSSL has no such suite | Not a server result. Rerun with a family your build carries. |
Common mistakes
Thresholds
What to check next
- How to check TLS version of a website: the suite name and the version are separate fields that are often confused.
- How to check if a website supports TLS 1.3: the three suites above only apply once 1.3 is on.
- How to check the TLS handshake: where the suite is chosen, and what an alert 40 looks like in the message flow.
- How to test SSL configuration: versions, suites and the certificate together.
FAQ
How to check cipher suites in Linux?
The same commands. openssl ciphers -v lists the local set and s_client -cipher probes a remote one. Neither needs a distribution specific package beyond openssl itself.
How to check SSL cipher suites with nmap?
nmap --script ssl-enum-ciphers -p 443 host enumerates the full list and grades it. It opens a connection per suite per version, which is heavy against a host you do not own, so keep it for your own infrastructure.
How do I check for weak ciphers specifically?
Probe the families rather than individual names: aNULL, eNULL, EXPORT, kRSA and SHA on CBC suites. Each accepted family is a finding on its own, and the family names survive OpenSSL version changes better than suite names.
Why does the server ignore my preference order sometimes?
A server can be configured to enforce its own order. When it does, both runs in step 4 return the same suite regardless of the order you sent, which is how you tell the two configurations apart.
Verified
Verified by Maks Vernyopenssl 3.1.1
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
intermediate7 minpublished updated Maks Verny