TLS

TLS

TLS security

TLS

Definition

Transport Layer Security (TLS) is a cryptographic protocol that provides privacy, data integrity, and authentication between communicating applications over a network. Operating at the transport layer (between TCP and application protocols like HTTP), TLS encrypts data in transit so that eavesdroppers see only ciphertext, authenticates the server (and optionally the client) via X.509 certificates, and ensures message integrity through cryptographic message authentication codes (MACs). TLS is the successor to SSL (Secure Sockets Layer) and is the foundation of HTTPS, securing virtually all modern web communication.

TLS 1.3, ratified as RFC 8446 in August 2018, represents a significant evolution of the protocol. It eliminates support for insecure cipher suites, reduces the handshake from two round trips to one (and zero for resumed connections via 0-RTT), removes vulnerable features like renegotiation and compression, and mandates forward secrecy for all cipher suites. These improvements make TLS 1.3 both faster and more secure than its predecessors, and it is the recommended minimum version for modern deployments.

In the context of security platforms performing External Attack Surface Management (EASM), TLS configuration analysis is a critical assessment dimension. Weak TLS configurations -- outdated protocol versions, insecure cipher suites, expired certificates, missing certificate transparency logs -- are among the most common and most impactful vulnerabilities discovered during attack surface assessments. A platform's TLS posture directly affects its security rating and compliance standing.

Historical Evolution

The evolution of TLS reflects two decades of cryptographic progress and attack discovery:

VersionYearKey ChangesCurrent Status
SSL 2.01995First public releaseDeprecated, insecure
SSL 3.01996Redesigned from SSL 2.0Deprecated (POODLE attack)
TLS 1.01999Renamed from SSL, minor changesDeprecated since 2020
TLS 1.12006Explicit IV, protection against CBC attacksDeprecated since 2020
TLS 1.22008AEAD cipher suites, SHA-256, extensibilityWidely deployed, still acceptable
TLS 1.320181-RTT handshake, mandatory PFS, reduced cipher suitesCurrent standard, recommended

Each version addressed vulnerabilities discovered in its predecessor. The shift from TLS 1.2 to TLS 1.3 was particularly dramatic: rather than patching individual vulnerabilities, TLS 1.3 removed entire categories of features that had proven to be security liabilities (renegotiation, compression, non-AEAD ciphers, RSA key exchange).

TLS 1.3 Protocol

TLS 1.3 simplifies the protocol significantly compared to TLS 1.2, removing entire categories of vulnerabilities by eliminating legacy features:

FeatureTLS 1.2TLS 1.3Security Impact
Handshake round trips2 RTT1 RTT (0-RTT resumption)Reduced latency
Key exchangeRSA, DHE, ECDHEECDHE, DHE onlyMandatory forward secrecy
Cipher suites37+ options5 optionsEliminated weak algorithms
CompressionSupportedRemovedPrevents CRIME/BREACH attacks
RenegotiationSupportedRemovedPrevents renegotiation attacks
Record paddingNot availableSupportedTraffic analysis resistance
0-RTT resumptionNot availableSupportedFast reconnection
Encrypted handshakeCertificate in plaintextCertificate encryptedServer identity protection

TLS 1.3 Cipher Suites

TLS 1.3 supports only five cipher suites, all providing authenticated encryption with associated data (AEAD):

Cipher SuiteKey ExchangeEncryptionHashStatus
TLS_AES_256_GCM_SHA384ECDHE/DHEAES-256-GCMSHA-384Recommended
TLS_AES_128_GCM_SHA256ECDHE/DHEAES-128-GCMSHA-256Recommended
TLS_CHACHA20_POLY1305_SHA256ECDHE/DHEChaCha20-Poly1305SHA-256Recommended (mobile)
TLS_AES_128_CCM_SHA256ECDHE/DHEAES-128-CCMSHA-256Optional
TLS_AES_128_CCM_8_SHA256ECDHE/DHEAES-128-CCM-8SHA-256IoT only

TLS Handshake

The TLS 1.3 handshake establishes a secure connection in a single round trip:

Client                                           Server

ClientHello
  + key_share
  + signature_algorithms
  + supported_versions    -------->
                                              ServerHello
                                              + key_share
                                    {EncryptedExtensions}
                                    {CertificateRequest*}
                                           {Certificate}
                                     {CertificateVerify}
                          <--------           {Finished}
{Certificate*}
{CertificateVerify*}
{Finished}                -------->
[Application Data]        <------->   [Application Data]

The key improvement over TLS 1.2 is that encrypted application data can begin flowing after just one round trip. The server's Certificate and CertificateVerify messages are encrypted (shown in {}), unlike TLS 1.2 where the server certificate was sent in plaintext, enabling passive observers to identify the server.

0-RTT Resumption

TLS 1.3 supports 0-RTT (zero round trip time) resumption for previously connected clients. The client sends application data alongside the ClientHello using a pre-shared key (PSK) from a previous session. This eliminates the handshake latency entirely for returning connections.

However, 0-RTT data is not protected against replay attacks -- an eavesdropper could capture and resend the 0-RTT data. Servers must therefore ensure that 0-RTT operations are idempotent or implement their own replay protection.

Forward Secrecy

Forward secrecy (also called perfect forward secrecy, PFS) ensures that compromise of a server's long-term private key does not compromise past session keys. In TLS 1.3, forward secrecy is mandatory because only ephemeral key exchange algorithms (ECDHE, DHE) are supported.

defmodule PrismaticPerimeter.TLS.ForwardSecrecyCheck do
  @moduledoc """
  Verifies that a target host supports forward secrecy.
  Part of the EASM TLS assessment pipeline.
  """

  @spec check_forward_secrecy(String.t(), pos_integer()) ::
    {:ok, :supported} | {:error, :not_supported | term()}
  def check_forward_secrecy(hostname, port \\ 443) do
    ecdhe_suites = [
      {:ecdhe_rsa, :aes_256_gcm, :aead, :sha384},
      {:ecdhe_rsa, :aes_128_gcm, :aead, :sha256},
      {:ecdhe_ecdsa, :aes_256_gcm, :aead, :sha384}
    ]

    ssl_opts = [
      verify: :verify_peer,
      cacerts: :public_key.cacerts_get(),
      ciphers: ecdhe_suites,
      server_name_indication: String.to_charlist(hostname)
    ]

    case :ssl.connect(String.to_charlist(hostname), port, ssl_opts, 10_000) do
      {:ok, socket} ->
        :ssl.close(socket)
        {:ok, :supported}
      {:error, _reason} ->
        {:error, :not_supported}
    end
  end
end

Certificate Management

X.509 certificates are the trust anchors of TLS, binding a public key to a domain identity. Certificate management involves issuance, validation, renewal, and revocation:

AspectDescriptionBest Practice
IssuanceObtaining a certificate from a Certificate Authority (CA)Use ACME protocol (Let's Encrypt) for automation
ValidationCertificate chain verification against trusted CA rootsValidate full chain, check revocation (OCSP)
RenewalReplacing certificates before expirationAutomate with 30-day pre-expiration renewal
RevocationInvalidating compromised certificatesOCSP stapling preferred over CRL
TransparencyPublic logging of issued certificatesMonitor CT logs for unauthorized issuance
Key rotationPeriodic replacement of private keysRotate with each renewal cycle
defmodule PrismaticPerimeter.TLS.CertificateAnalyzer do
  @moduledoc """
  Analyzes X.509 certificates for security assessment.
  Extracts validity, chain completeness, and compliance data.
  """

  @type cert_assessment :: %{
    subject: String.t(),
    issuer: String.t(),
    valid_from: DateTime.t(),
    valid_until: DateTime.t(),
    days_remaining: integer(),
    key_algorithm: String.t(),
    key_size: pos_integer(),
    signature_algorithm: String.t(),
    san_domains: [String.t()],
    chain_complete: boolean(),
    ct_logged: boolean()
  }

  @spec analyze(binary()) :: {:ok, cert_assessment()} | {:error, term()}
  def analyze(der_cert) do
    case :public_key.pkix_decode_cert(der_cert, :otp) do
      {:OTPCertificate, tbs, _, _} ->
        {:ok, extract_assessment(tbs)}
      _ ->
        {:error, :invalid_certificate}
    end
  end
end

HTTPS Enforcement

HTTPS (HTTP over TLS) is the standard mechanism for securing web traffic. Proper HTTPS enforcement requires several complementary measures:

MechanismPurposeImplementation
HTTP-to-HTTPS redirectForce all traffic to encrypted channel301 redirect on port 80
HSTSPrevent protocol downgrade attacksStrict-Transport-Security header
HSTS PreloadBrowser-level HTTPS enforcementSubmit to HSTS preload list
Certificate TransparencyPublic audit of certificate issuanceCT log monitoring
OCSP StaplingEfficient certificate revocation checkingServer-side OCSP response caching
CAA RecordsRestrict which CAs can issue certificatesDNS CAA record publication

HTTP Strict Transport Security (HSTS) is particularly important because it instructs browsers to always use HTTPS for the domain, even if the user types http:// or follows an HTTP link. The max-age directive specifies how long the browser should remember this preference, and includeSubDomains extends the policy to all subdomains.

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Context in Prismatic

The Prismatic Platform enforces TLS across all external communication paths. Production deployments on Fly.io terminate TLS at the edge with automatic certificate management via Let's Encrypt. The platform's Phoenix endpoints are configured with force_ssl: true, redirecting all HTTP requests to HTTPS and setting HSTS headers with a two-year max-age.

defmodule PrismaticWeb.Endpoint do
  @moduledoc "Phoenix endpoint with TLS enforcement configuration."
  use Phoenix.Endpoint, otp_app: :prismatic_web

  # Production TLS configuration
  # config/prod.exs
  # config :prismatic_web, PrismaticWeb.Endpoint,
  #   url: [host: "prismatic-prod.fly.dev", port: 443],
  #   https: [
  #     port: 4001,
  #     cipher_suite: :strong,
  #     versions: [:"tlsv1.3", :"tlsv1.2"],
  #     certfile: System.get_env("TLS_CERT_PATH"),
  #     keyfile: System.get_env("TLS_KEY_PATH"),
  #     cacertfile: System.get_env("TLS_CA_PATH")
  #   ],
  #   force_ssl: [
  #     hsts: true,
  #     rewrite_on: [:x_forwarded_proto]
  #   ]
end

Internally, the platform uses TLS for inter-service communication when services are distributed across nodes. The Erlang/OTP distribution protocol can be configured with TLS for cluster communication, ensuring that BEAM-level messages between nodes are encrypted in transit.

EASM TLS Assessment

The Prismatic Perimeter EASM module actively assesses TLS configurations of discovered attack surface assets, factoring certificate validity, protocol versions, cipher suite strength, and certificate transparency compliance into security ratings:

CheckWeightFinding Examples
Protocol versionHighTLS 1.0/1.1 present (critical), TLS 1.3 missing (warning)
Certificate validityCriticalExpired certificate, wrong hostname, self-signed
Certificate chainHighIncomplete chain, untrusted CA, missing intermediates
Cipher suite strengthHighRC4, DES, export-grade ciphers (critical)
Forward secrecyMediumNon-ECDHE key exchange (warning)
HSTS configurationMediumMissing HSTS, short max-age, missing preload
Certificate transparencyLowMissing CT logs (informational)
OCSP staplingLowMissing OCSP staple (informational)
CAA recordsLowMissing DNS CAA records (informational)
defmodule PrismaticPerimeter.TLSChecker do
  @moduledoc """
  Comprehensive TLS configuration assessment for EASM.
  Checks protocol versions, cipher suites, certificates,
  and security headers for discovered assets.
  """

  @spec check_tls(String.t(), pos_integer()) ::
    {:ok, tls_assessment()} | {:error, term()}
  def check_tls(hostname, port \\ 443) do
    ssl_opts = [
      verify: :verify_peer,
      cacerts: :public_key.cacerts_get(),
      depth: 4,
      server_name_indication: String.to_charlist(hostname),
      customize_hostname_check: [
        match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
      ]
    ]

    case :ssl.connect(String.to_charlist(hostname), port, ssl_opts, 10_000) do
      {:ok, socket} ->
        assessment = %{
          protocol: extract_version(socket),
          cipher_suite: extract_cipher(socket),
          certificate: analyze_peer_cert(socket),
          chain_valid: true,
          forward_secrecy: check_pfs(socket),
          hostname_match: true
        }
        :ssl.close(socket)
        {:ok, assessment}

      {:error, reason} ->
        {:error, {:connection_failed, reason}}
    end
  end

  @spec calculate_tls_score(tls_assessment()) :: {:ok, float()}
  def calculate_tls_score(assessment) do
    score =
      protocol_score(assessment.protocol) * 0.3 +
      cipher_score(assessment.cipher_suite) * 0.25 +
      certificate_score(assessment.certificate) * 0.25 +
      pfs_score(assessment.forward_secrecy) * 0.1 +
      header_score(assessment) * 0.1

    {:ok, score}
  end
end

Weak or expired TLS is flagged as a critical finding in compliance assessments for both NIS2 Directive and ZKB 264/2025 frameworks, which mandate encryption of data in transit for all network-accessible services.

TLS in the Elixir/OTP Ecosystem

The BEAM virtual machine provides TLS support through the Erlang :ssl application, which wraps OpenSSL (or LibreSSL on some platforms). Phoenix applications configure TLS at the endpoint level, and the Erlang runtime handles all cryptographic operations:

defmodule PrismaticCluster.DistributionTLS do
  @moduledoc """
  TLS configuration for BEAM distribution protocol.
  Encrypts inter-node communication in distributed clusters.
  """

  @spec distribution_ssl_opts() :: keyword()
  def distribution_ssl_opts do
    [
      certfile: System.get_env("DIST_CERT_PATH"),
      keyfile: System.get_env("DIST_KEY_PATH"),
      cacertfile: System.get_env("DIST_CA_PATH"),
      verify: :verify_peer,
      secure_renegotiate: true,
      versions: [:"tlsv1.3"],
      fail_if_no_peer_cert: true
    ]
  end
end

Common TLS Misconfigurations

MisconfigurationRiskDetectionRemediation
Legacy protocol supportDowngrade attacks (POODLE, BEAST)Protocol version scanDisable TLS 1.0/1.1
Weak cipher suitesCryptographic attacks (SWEET32, LUCKY13)Cipher enumerationRestrict to TLS 1.3 suites
Expired certificatesTrust failure, user warningsCertificate expiry checkAutomated renewal (ACME)
Self-signed certificatesNo third-party trust validationCA chain verificationUse public CA (Let's Encrypt)
Incomplete certificate chainIntermittent trust failuresChain validationInclude all intermediate certificates
Missing HSTSProtocol downgrade riskHeader inspectionAdd HSTS with preload
Wildcard certificate overuseExpanded blast radiusCertificate scope analysisScoped certificates per service
No OCSP staplingRevocation check latencyOCSP configuration checkEnable OCSP stapling
RSA key exchangeNo forward secrecyKey exchange analysisRequire ECDHE only

Security Rating Impact

TLS findings directly impact the security ratings computed by Prismatic Perimeter:

Finding SeverityRating ImpactGrade Effect
Expired certificate-200 pointsDrops to D or F
TLS 1.0/1.1 enabled-100 pointsDrops one grade
Missing forward secrecy-50 pointsMay drop one grade
Missing HSTS-25 pointsMinor impact
Missing CT logs-10 pointsInformational
  • Encryption at Rest - Complementary protection for stored data
  • EASM - External attack surface management assessing TLS configurations
  • Attack Surface - TLS posture as a key component of exposed surface
  • JWT - Tokens that must be transported over TLS
  • OAuth2 - Authorization protocol requiring TLS for secure token exchange
  • API Gateway - TLS termination point for API traffic
  • Shodan - Discovers exposed services including TLS configurations
  • Censys - Certificate transparency and TLS scanning platform
  • Risk Score - TLS findings weighted in overall risk calculations
  • Observability - Monitoring TLS certificate expiry and handshake errors
  • Phoenix - Framework configuring TLS at the endpoint level

See Also


Connect & Contribute

Created by Tomas Korcak (korczis) | Open Source under GHL