Skip to content

fix: do not negotiate TLS 1.3 when only TLS 1.2 ciphers are supplied#303

Merged
zookzook merged 1 commit into
zookzook:masterfrom
DmitryKorolev:fix/tls13-cipher-version-fallback
May 27, 2026
Merged

fix: do not negotiate TLS 1.3 when only TLS 1.2 ciphers are supplied#303
zookzook merged 1 commit into
zookzook:masterfrom
DmitryKorolev:fix/tls13-cipher-version-fallback

Conversation

@DmitryKorolev

Copy link
Copy Markdown
Contributor

When the caller passes ssl_opts.ciphers without an explicit ssl_opts.versions, Erlang's :ssl will still attempt TLS 1.3 negotiation if the OTP build supports it. If none of the supplied ciphers match a TLS 1.3 suite, the handshake fails with no automatic fallback to TLS 1.2.

In practice this surfaces when the MongoDB server starts negotiating TLS 1.3 (e.g. after a cluster upgrade) and the user's :ciphers list only contains TLS-1.2-era suites.

Mongo.MongoDBConnection.Utils.maybe_restrict_versions/1 detects the mismatch and pins :versions to [:"tlsv1.2"] when the supplied ciphers do not include any TLS 1.3 suite. Callers who explicitly set :versions are left untouched. The override is logged at Logger.warning so operators see it in production where info-level logs are typically filtered.

Also normalizes opts[:ssl_opts] to [] on the IP-address branch of defp ssl/2; previously that branch could pass nil to :ssl.connect/3 if the caller omitted :ssl_opts.

Unit tests cover charlist / atom / binary / map cipher shapes, mixed TLS 1.2 + TLS 1.3 lists, and the no-op cases (:ciphers nil/empty, :versions already set).

When the caller passes `ssl_opts.ciphers` without an explicit
`ssl_opts.versions`, Erlang's `:ssl` will still attempt TLS 1.3
negotiation if the OTP build supports it. If none of the supplied
ciphers match a TLS 1.3 suite, the handshake fails with no automatic
fallback to TLS 1.2.

In practice this surfaces when the MongoDB server starts negotiating
TLS 1.3 (e.g. after a cluster upgrade) and the user's `:ciphers` list
only contains TLS-1.2-era suites.

`Mongo.MongoDBConnection.Utils.maybe_restrict_versions/1` detects the
mismatch and pins `:versions` to `[:"tlsv1.2"]` when the supplied
ciphers do not include any TLS 1.3 suite. Callers who explicitly set
`:versions` are left untouched. The override is logged at
`Logger.warning` so operators see it in production where info-level
logs are typically filtered.

Also normalizes `opts[:ssl_opts]` to `[]` on the IP-address branch of
`defp ssl/2`; previously that branch could pass `nil` to
`:ssl.connect/3` if the caller omitted `:ssl_opts`.

Unit tests cover charlist / atom / binary / map cipher shapes, mixed
TLS 1.2 + TLS 1.3 lists, and the no-op cases (`:ciphers` nil/empty,
`:versions` already set). Tests skip cleanly on OTP builds without
TLS 1.3.
@zookzook zookzook merged commit b1f130c into zookzook:master May 27, 2026
5 checks passed
@zookzook

Copy link
Copy Markdown
Owner

Thanks for this nice PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants