You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
During a TLS 1.2 handshake, if the server's CertificateRequest message contains a certificate_authorities entry whose DN violates an X.520 type constraint (real-world example: countryName encoded as UTF8String instead of PrintableString), the client aborts the whole handshake with a fatal decode_error alert (handshake_decode_error). This happens even when no client certificate is configured, and regardless of verify mode or any other ssl option.
Root cause: ssl_handshake:decode_cert_auths/2 calls public_key:pkix_normalize_name/1 on every advertised CA name with no error handling:
pkix_normalize_name/1 raises on the non-conformant DN, the error propagates into the try in tls_handshake:get_tls_handshakes_aux/4, and becomes ?ALERT_REC(?FATAL, ?DECODE_ERROR, handshake_decode_error) (tls_handshake.erl:460 on maint-28).
The certificate_authorities list is advisory — a hint for client certificate selection (RFC 5246 §7.4.4). Other TLS implementations (OpenSSL/curl, Go, Java, .NET, browsers) treat these entries leniently or as opaque bytes and interoperate fine with such servers. As a result, Erlang/Elixir clients (raw ssl and everything built on it: httpc, Mint, Finch, hackney) cannot connect at all to affected servers. In practice these are typically IIS servers configured to advertise their machine trust store, which may contain badly-encoded third-party CA certificates that the server operator does not control either.
To Reproduce
Server-independent repro — the DN below is a real CA name harvested from a live server's CertificateRequest (its countryName is UTF8String-encoded, tag 12, where PrintableString, tag 19, is required):
1>Der=base64:decode("MHAxCzAJBgNVBAYMAkJSMRMwEQYDVQQKDApJQ1AtQnJhc2lsMTQwMgYDVQQLDCtBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhIHY1MRYwFAYDVQQDDA1BQyBTeW5ndWxhcklE").
2>public_key:pkix_normalize_name(Der).
**exceptionerror: nomatchofrighthandsidevalue
{error,{asn1,{{'Type not compatible with table constraint',
{error,{asn1,{wrong_tag,{{expected,19},{got,12,{12,"BR"}}}}}}},
[...]}}}
openssl asn1parse decodes the same DN without complaint: C=BR, O=ICP-Brasil, OU=Autoridade Certificadora Raiz Brasileira v5, CN=AC SyngularID (all attributes UTF8STRING).
Live handshake repro against a public server that currently exhibits this (the Brazilian national NFS-e homologation environment; its CertificateRequest advertises 223 CA names, one of which is the DN above — no client certificate needed):
1>ssl:connect("adn.producaorestrita.nfse.gov.br", 443,
[{verify, verify_none}, {versions, ['tlsv1.2']}], 20000).
{error,{tls_alert,
{decode_error,
"TLS client: In state certify at tls_handshake.erl:460 generated CLIENT ALERT: Fatal - Decode Error\n handshake_decode_error"}}}
openssl s_client -connect adn.producaorestrita.nfse.gov.br:443 -servername adn.producaorestrita.nfse.gov.br -tls1_2 completes the handshake against the same server.
The failure is independent of verify, cacerts, depth, ciphers, signature_algs, and of whether certfile/keyfile are configured.
Expected behavior
Undecodable entries in the advisory certificate_authorities list should be skipped (optionally logged), not abort the handshake. That would match the tolerance the ssl/public_key apps already apply elsewhere:
Wrapping the public_key:pkix_normalize_name/1 call in decode_cert_auths/2 in a try/catch and skipping entries that fail to decode looks like a small, contained change, mirroring the existing patterns.
Affected versions
Reproduced on OTP 28 (erts-16.4.0.3, ssl 11.6.0.3, public_key 1.20.3.3, asn1 5.4.3), macOS aarch64. The unguarded code is identical on maint-28, maint and master as of 2026-07-05, so presumably all supported releases are affected.
Additional context
Related issues: #8058 (same crash class in the server Certificate path, fixed by #8256) and #10605 (open enhancement requesting lenient DN decoding in public_key:pkix_decode_cert/2).
Describe the bug
During a TLS 1.2 handshake, if the server's
CertificateRequestmessage contains acertificate_authoritiesentry whose DN violates an X.520 type constraint (real-world example:countryNameencoded as UTF8String instead of PrintableString), the client aborts the whole handshake with a fataldecode_erroralert (handshake_decode_error). This happens even when no client certificate is configured, and regardless ofverifymode or any otherssloption.Root cause:
ssl_handshake:decode_cert_auths/2callspublic_key:pkix_normalize_name/1on every advertised CA name with no error handling:pkix_normalize_name/1raises on the non-conformant DN, the error propagates into thetryintls_handshake:get_tls_handshakes_aux/4, and becomes?ALERT_REC(?FATAL, ?DECODE_ERROR, handshake_decode_error)(tls_handshake.erl:460onmaint-28).The
certificate_authoritieslist is advisory — a hint for client certificate selection (RFC 5246 §7.4.4). Other TLS implementations (OpenSSL/curl, Go, Java, .NET, browsers) treat these entries leniently or as opaque bytes and interoperate fine with such servers. As a result, Erlang/Elixir clients (rawssland everything built on it:httpc, Mint, Finch, hackney) cannot connect at all to affected servers. In practice these are typically IIS servers configured to advertise their machine trust store, which may contain badly-encoded third-party CA certificates that the server operator does not control either.To Reproduce
Server-independent repro — the DN below is a real CA name harvested from a live server's
CertificateRequest(itscountryNameis UTF8String-encoded, tag 12, where PrintableString, tag 19, is required):openssl asn1parsedecodes the same DN without complaint:C=BR, O=ICP-Brasil, OU=Autoridade Certificadora Raiz Brasileira v5, CN=AC SyngularID(all attributes UTF8STRING).Live handshake repro against a public server that currently exhibits this (the Brazilian national NFS-e homologation environment; its
CertificateRequestadvertises 223 CA names, one of which is the DN above — no client certificate needed):openssl s_client -connect adn.producaorestrita.nfse.gov.br:443 -servername adn.producaorestrita.nfse.gov.br -tls1_2completes the handshake against the same server.The failure is independent of
verify,cacerts,depth,ciphers,signature_algs, and of whethercertfile/keyfileare configured.Expected behavior
Undecodable entries in the advisory
certificate_authoritieslist should be skipped (optionally logged), not abort the handshake. That would match the tolerance the ssl/public_key apps already apply elsewhere:ssl_handshake:decode_sign_alg/2silently ignores unknown signature algorithms;cacertsare skipped with a log entry;Certificatemessage — butdecode_cert_auths/2was not covered by that fix and remains unguarded onmaint-28,maintandmastertoday.Wrapping the
public_key:pkix_normalize_name/1call indecode_cert_auths/2in a try/catch and skipping entries that fail to decode looks like a small, contained change, mirroring the existing patterns.Affected versions
Reproduced on OTP 28 (erts-16.4.0.3, ssl 11.6.0.3, public_key 1.20.3.3, asn1 5.4.3), macOS aarch64. The unguarded code is identical on
maint-28,maintandmasteras of 2026-07-05, so presumably all supported releases are affected.Additional context
Related issues: #8058 (same crash class in the server
Certificatepath, fixed by #8256) and #10605 (open enhancement requesting lenient DN decoding inpublic_key:pkix_decode_cert/2).