The most surprising thing about Nmap’s TLS scanning capabilities is that it can reveal a server’s entire TLS certificate chain and handshake details without ever actually establishing a full, encrypted connection.

Let’s see this in action. Imagine scanning a web server at example.com on its HTTPS port (443).

nmap -p 443 --script ssl-cert,ssl-enum-ciphers example.com

Here’s a snippet of what you might see for example.com:

PORT    STATE SERVICE
443/tcp open  https
| ssl-cert: Subject: CN=example.com
|   Issuer: CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
|   Not before: 2023-10-27 00:00:00 UTC
|   Not after: 2024-01-25 23:59:59 UTC
|   SHA1: a1b2c3d4e5f678901234567890abcdef12345678
|   SHA256: fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210
|   Key usage: Digital Signature, Key Encipherment
|   Extended key usage: Server Auth, Client Auth
|   Issuer:
|     CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
|     -- chain --
|     CN=ISRG Root X1, O=Internet Security Research Group, C=US
|
| ssl-enum-ciphers:
|   TLSv1.3:
|     ciphers:
|       TLS_AES_256_GCM_SHA384 (kx: P521) - strong
|       TLS_CHACHA20_POLY1305_SHA256 (kx: P521) - strong
|       TLS_AES_128_GCM_SHA256 (kx: P521) - medium
|     compressors:
|       NULL
|   TLSv1.2:
|     ECDHE-RSA-AES256-GCM-SHA384 (kx: P521) - strong
|     ECDHE-RSA-AES128-GCM-SHA256 (kx: P521) - medium
|     ECDHE-RSA-CHACHA20-POLY1305 (kx: P521) - strong
|     ECDHE-RSA-AES256-SHA384 (kx: P521) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P521) - medium
|     ECDHE-RSA-AES256-SHA (kx: P521) - high
|     ECDHE-RSA-AES128-SHA (kx: P521) - medium
|     DHE-RSA-AES256-GCM-SHA384 (kx: P521) - strong
|     DHE-RSA-AES128-GCM-SHA256 (kx: P521) - medium
|     DHE-RSA-AES256-SHA256 (kx: P521) - high
|     DHE-RSA-AES128-SHA256 (kx: P521) - medium
|     DHE-RSA-AES256-SHA (kx: P521) - high
|     DHE-RSA-AES128-SHA (kx: P521) - medium
|     RSA-AES256-GCM-SHA384 (kx: P521) - strong
|     RSA-AES128-GCM-SHA256 (kx: P521) - medium
|     RSA-AES256-SHA256 (kx: P521) - high
|     RSA-AES128-SHA256 (kx: P521) - medium
|     RSA-AES256-SHA (kx: P521) - high
|     RSA-AES128-SHA (kx: P521) - medium
|     ECDHE-RSA-AES256-GCM-SHA384 (kx: P384) - strong
|     ECDHE-RSA-AES128-GCM-SHA256 (kx: P384) - medium
|     ECDHE-RSA-CHACHA20-POLY1305 (kx: P384) - strong
|     ECDHE-RSA-AES256-SHA384 (kx: P384) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P384) - medium
|     ECDHE-RSA-AES256-SHA (kx: P384) - high
|     ECDHE-RSA-AES128-SHA (kx: P384) - medium
|     DHE-RSA-AES256-GCM-SHA384 (kx: P384) - strong
|     DHE-RSA-AES128-GCM-SHA256 (kx: P384) - medium
|     DHE-RSA-AES256-SHA256 (kx: P384) - high
|     DHE-RSA-AES128-SHA256 (kx: P384) - medium
|     DHE-RSA-AES256-SHA (kx: P384) - high
|     DHE-RSA-AES128-SHA (kx: P384) - medium
|     RSA-AES256-GCM-SHA384 (kx: P384) - strong
|     RSA-AES128-GCM-SHA256 (kx: P384) - medium
|     RSA-AES256-SHA256 (kx: P384) - high
|     RSA-AES128-SHA256 (kx: P384) - medium
|     RSA-AES256-SHA (kx: P384) - high
|     RSA-AES128-SHA (kx: P384) - medium
|     ECDHE-RSA-AES256-GCM-SHA384 (kx: P256) - strong
|     ECDHE-RSA-AES128-GCM-SHA256 (kx: P256) - medium
|     ECDHE-RSA-CHACHA20-POLY1305 (kx: P256) - strong
|     ECDHE-RSA-AES256-SHA384 (kx: P256) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P256) - medium
|     ECDHE-RSA-AES256-SHA (kx: P256) - high
|     ECDHE-RSA-AES128-SHA (kx: P256) - medium
|     DHE-RSA-AES256-GCM-SHA384 (kx: P256) - strong
|     DHE-RSA-AES128-GCM-SHA256 (kx: P256) - medium
|     DHE-RSA-AES256-SHA256 (kx: P256) - high
|     DHE-RSA-AES128-SHA256 (kx: P256) - medium
|     DHE-RSA-AES256-SHA (kx: P256) - high
|     DHE-RSA-AES128-SHA (kx: P256) - medium
|     RSA-AES256-GCM-SHA384 (kx: P256) - strong
|     RSA-AES128-GCM-SHA256 (kx: P256) - medium
|     RSA-AES256-SHA256 (kx: P256) - high
|     RSA-AES128-SHA256 (kx: P256) - medium
|     RSA-AES256-SHA (kx: P256) - high
|     RSA-AES128-SHA (kx: P256) - medium
|   TLSv1.1:
|     ECDHE-RSA-AES256-GCM-SHA384 (kx: P521) - strong
|     ECDHE-RSA-AES128-GCM-SHA256 (kx: P521) - medium
|     ECDHE-RSA-CHACHA20-POLY1305 (kx: P521) - strong
|     ECDHE-RSA-AES256-SHA384 (kx: P521) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P521) - medium
|     ECDHE-RSA-AES256-SHA (kx: P521) - high
|     ECDHE-RSA-AES128-SHA (kx: P521) - medium
|     DHE-RSA-AES256-GCM-SHA384 (kx: P521) - strong
|     DHE-RSA-AES128-GCM-SHA256 (kx: P521) - medium
|     DHE-RSA-AES256-SHA256 (kx: P521) - high
|     DHE-RSA-AES128-SHA256 (kx: P521) - medium
|     DHE-RSA-AES256-SHA (kx: P521) - high
|     DHE-RSA-AES128-SHA (kx: P521) - medium
|     RSA-AES256-GCM-SHA384 (kx: P521) - strong
|     RSA-AES128-GCM-SHA256 (kx: P521) - medium
|     RSA-AES256-SHA256 (kx: P521) - high
|     RSA-AES128-SHA256 (kx: P521) - medium
|     RSA-AES256-SHA (kx: P521) - high
|     RSA-AES128-SHA (kx: P521) - medium
|     ECDHE-RSA-AES256-GCM-SHA384 (kx: P384) - strong
|     ECDHE-RSA-AES128-GCM-SHA256 (kx: P384) - medium
|     ECDHE-RSA-CHACHA20-POLY1305 (kx: P384) - strong
|     ECDHE-RSA-AES256-SHA384 (kx: P384) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P384) - medium
|     ECDHE-RSA-AES256-SHA (kx: P384) - high
|     ECDHE-RSA-AES128-SHA (kx: P384) - medium
|     DHE-RSA-AES256-GCM-SHA384 (kx: P384) - strong
|     DHE-RSA-AES128-GCM-SHA256 (kx: P384) - medium
|     DHE-RSA-AES256-SHA256 (kx: P384) - high
|     DHE-RSA-AES128-SHA256 (kx: P384) - medium
|     DHE-RSA-AES256-SHA (kx: P384) - high
|     DHE-RSA-AES128-SHA (kx: P384) - medium
|     RSA-AES256-GCM-SHA384 (kx: P384) - strong
|     RSA-AES128-GCM-SHA256 (kx: P384) - medium
|     RSA-AES256-SHA256 (kx: P384) - high
|     RSA-AES128-SHA256 (kx: P384) - medium
|     RSA-AES256-SHA (kx: P384) - high
|     RSA-AES128-SHA (kx: P384) - medium
|     ECDHE-RSA-AES256-GCM-SHA384 (kx: P256) - strong
|     ECDHE-RSA-AES128-GCM-SHA256 (kx: P256) - medium
|     ECDHE-RSA-CHACHA20-POLY1305 (kx: P256) - strong
|     ECDHE-RSA-AES256-SHA384 (kx: P256) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P256) - medium
|     ECDHE-RSA-AES256-SHA (kx: P256) - high
|     ECDHE-RSA-AES128-SHA (kx: P256) - medium
|     DHE-RSA-AES256-GCM-SHA384 (kx: P256) - strong
|     DHE-RSA-AES128-GCM-SHA256 (kx: P256) - medium
|     DHE-RSA-AES256-SHA256 (kx: P256) - high
|     DHE-RSA-AES128-SHA256 (kx: P256) - medium
|     DHE-RSA-AES256-SHA (kx: P256) - high
|     DHE-RSA-AES128-SHA (kx: P256) - medium
|     RSA-AES256-GCM-SHA384 (kx: P256) - strong
|     RSA-AES128-GCM-SHA256 (kx: P256) - medium
|     RSA-AES256-SHA256 (kx: P256) - high
|     RSA-AES128-SHA256 (kx: P256) - medium
|     RSA-AES256-SHA (kx: P256) - high
|     RSA-AES128-SHA (kx: P256) - medium
|   TLSv1.0:
|     ECDHE-RSA-AES256-CBC-SHA384 (kx: P521) - high
|     ECDHE-RSA-AES128-CBC-SHA256 (kx: P521) - medium
|     ECDHE-RSA-AES256-SHA384 (kx: P521) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P521) - medium
|     ECDHE-RSA-AES256-SHA (kx: P521) - high
|     ECDHE-RSA-AES128-SHA (kx: P521) - medium
|     DHE-RSA-AES256-CBC-SHA384 (kx: P521) - high
|     DHE-RSA-AES128-CBC-SHA256 (kx: P521) - medium
|     DHE-RSA-AES256-SHA256 (kx: P521) - high
|     DHE-RSA-AES128-SHA256 (kx: P521) - medium
|     DHE-RSA-AES256-SHA (kx: P521) - high
|     DHE-RSA-AES128-SHA (kx: P521) - medium
|     RSA-AES256-CBC-SHA384 (kx: P521) - high
|     RSA-AES128-CBC-SHA256 (kx: P521) - medium
|     RSA-AES256-SHA256 (kx: P521) - high
|     RSA-AES128-SHA256 (kx: P521) - medium
|     RSA-AES256-SHA (kx: P521) - high
|     RSA-AES128-SHA (kx: P521) - medium
|     ECDHE-RSA-AES256-CBC-SHA384 (kx: P384) - high
|     ECDHE-RSA-AES128-CBC-SHA256 (kx: P384) - medium
|     ECDHE-RSA-AES256-SHA384 (kx: P384) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P384) - medium
|     ECDHE-RSA-AES256-SHA (kx: P384) - high
|     ECDHE-RSA-AES128-SHA (kx: P384) - medium
|     DHE-RSA-AES256-CBC-SHA384 (kx: P384) - high
|     DHE-RSA-AES128-CBC-SHA256 (kx: P384) - medium
|     DHE-RSA-AES256-SHA256 (kx: P384) - high
|     DHE-RSA-AES128-SHA256 (kx: P384) - medium
|     DHE-RSA-AES256-SHA (kx: P384) - high
|     DHE-RSA-AES128-SHA (kx: P384) - medium
|     RSA-AES256-CBC-SHA384 (kx: P384) - high
|     RSA-AES128-CBC-SHA256 (kx: P384) - medium
|     RSA-AES256-SHA256 (kx: P384) - high
|     RSA-AES128-SHA256 (kx: P384) - medium
|     RSA-AES256-SHA (kx: P384) - high
|     RSA-AES128-SHA (kx: P384) - medium
|     ECDHE-RSA-AES256-CBC-SHA384 (kx: P256) - high
|     ECDHE-RSA-AES128-CBC-SHA256 (kx: P256) - medium
|     ECDHE-RSA-AES256-SHA384 (kx: P256) - high
|     ECDHE-RSA-AES128-SHA256 (kx: P256) - medium
|     ECDHE-RSA-AES256-SHA (kx: P256) - high
|     ECDHE-RSA-AES128-SHA (kx: P256) - medium
|     DHE-RSA-AES256-CBC-SHA384 (kx: P256) - high
|     DHE-RSA-AES128-CBC-SHA256 (kx: P256) - medium
|     DHE-RSA-AES256-SHA256 (kx: P256) - high
|     DHE-RSA-AES128-SHA256 (kx: P256) - medium
|     DHE-RSA-AES256-SHA (kx: P256) - high
|     DHE-RSA-AES128-SHA (kx: P256) - medium
|     RSA-AES256-CBC-SHA384 (kx: P256) - high
|     RSA-AES128-CBC-SHA256 (kx: P256) - medium
|     RSA-AES256-SHA256 (kx: P256) - high
|     RSA-AES128-SHA256 (kx: P256) - medium
|     RSA-AES256-SHA (kx: P256) - high
|     RSA-AES128-SHA (kx: P256) - medium

This output is invaluable for understanding a server’s TLS security posture.

The Certificate (ssl-cert script):

This part of the output gives you the full details of the server’s X.509 certificate. You’ll see:

  • Subject: The identity of the server (e.g., CN=example.com).
  • Issuer: Who signed the certificate. This is crucial for verifying trust. If the issuer isn’t trusted by your client, the connection will fail.
  • Validity Period: Not before and Not after dates. Essential for detecting expired certificates.
  • Fingerprints: SHA1 and SHA256 hashes of the certificate. Useful for unique identification and comparison.
  • Key Usage & Extended Key Usage: What the certificate is allowed to be used for (e.g., Server Auth for TLS/SSL).
  • Certificate Chain: The full chain of trust, from the end-entity certificate up to the root CA. Nmap fetches this by asking the server to send its certificate and any intermediate certificates it has.

The Ciphers (ssl-enum-ciphers script):

This script probes the server to see which TLS versions and cipher suites it supports. It does this by attempting a handshake with each combination and observing the result.

  • TLS Versions: You’ll see support listed for TLSv1.3, TLSv1.2, TLSv1.1, and even older (and insecure) TLSv1.0.
  • Cipher Suites: For each TLS version, Nmap lists the available cipher suites. These are combinations of key exchange, authentication, bulk encryption, and message authentication code (MAC).
  • Key Exchange (kx): Indicates how the server and client will agree on a symmetric encryption key (e.g., P521 for Elliptic Curve Diffie-Hellman with a 521-bit curve, RSA for traditional key transport).
  • Strength Ratings: Nmap attempts to categorize cipher suites as strong, medium, weak, or insecure based on known vulnerabilities and cryptographic strength. For example, TLS_AES_256_GCM_SHA384 is generally considered strong for TLS 1.3, while older cipher suites like TLS_RSA_WITH_RC4_128_SHA would be flagged as insecure.

How it Works (The Magic):

Nmap doesn’t complete the TLS handshake. Instead, it sends a ClientHello message and then analyzes the ServerHello and the subsequent certificate exchange. It doesn’t need to decrypt anything because it’s primarily interested in the metadata of the TLS negotiation itself: what options the server offered, what it accepted, and what certificate it presented. It’s like peeking at the menu before ordering, rather than actually eating the meal.

The ssl-cert script works by requesting the certificate from the server during the TLS handshake. The server, as part of the handshake, sends its certificate and any intermediate certificates it has. Nmap captures this data.

The ssl-enum-ciphers script is more active. It sends multiple ClientHello messages, each with a different set of supported ciphers or TLS versions, and observes the server’s ServerHello response. If the server accepts a specific cipher suite, Nmap records it. If the server rejects it or offers a different one, Nmap notes that too. This allows it to build a comprehensive list of what the server is willing to negotiate.

This information is critical for security audits. You can quickly identify:

  • Outdated TLS versions: Servers still offering TLSv1.0 or TLSv1.1 are vulnerable to known attacks.
  • Weak cipher suites: Support for ciphers using RC4, DES, or older MD5-based MACs indicates significant security weaknesses.
  • Certificate expiry: Expired certificates can lead to trust issues and connection failures.
  • Mismatched hostnames: The certificate’s Subject Alternative Names (SANs) or Common Name (CN) might not match the hostname you’re scanning, causing browser warnings.
  • Trust chain issues: If the intermediate or root CAs are not trusted by the client, the connection will be refused.

One subtle point is that Nmap’s cipher strength ratings are based on known vulnerabilities and best practices at the time the Nmap version was released. For the absolute latest, cutting-edge cryptographic recommendations, you might need to cross-reference with current NIST or IETF guidelines, as the landscape of cryptographic weaknesses evolves rapidly.

After ensuring your server supports strong TLS ciphers and has a valid certificate, the next step in hardening your TLS configuration is often to configure specific TLS extensions like Server Name Indication (SNI) for hosts with multiple certificates on one IP, or to tune session resumption parameters.

Want structured learning?

Take the full Nmap course →