Mensagem de erro
received fatal alert: HandshakeFailure
O reqwest o imprime no fim da cadeia de erros; o ureq, como “io: received fatal alert: HandshakeFailure”. Diante de um servidor só com TLS 1.0 (tls-v1-0.badssl.com), nosso cliente rustls recebeu esse mesmo alerta. Outros alertas aparecem com os próprios nomes do rustls depois de “received fatal alert: ”.
rustls (via reqwest, ureq, tonic) — rustls::Error::AlertReceived(HandshakeFailure)
O que significa
O servidor respondeu ao ClientHello do rustls com o alerta TLS 40 (handshake_failure). O rustls implementa de propósito só o TLS moderno: TLS 1.2 e 1.3 com troca de chaves ECDHE e cifras AEAD. Servidores que exigem troca de chaves RSA, cipher suites CBC, TLS 1.0/1.1 ou um certificado de cliente rejeitam o rustls dessa forma.
Por que acontece
Nenhuma cipher suite que o rustls implemente
comumServidores legados limitados a suites com troca de chaves RSA, suites CBC-SHA ou suites 3DES não têm nada em comum com o rustls.
O servidor só fala TLS 1.0 ou 1.1
comumO rustls não implementa versões do TLS anteriores à 1.2.
O servidor exige um certificado de cliente
ocasionalNo TLS 1.2, endpoints com TLS mútuo respondem com handshake_failure a um cliente que não apresenta certificado.
Como corrigir
- 1.
Verificar o que o servidor oferece
Se ele não oferecer nenhuma suite ECDHE + AEAD, o servidor precisa ser modernizado.
bash # What does the server accept? rustls offers TLS 1.2/1.3 with ECDHE + AES-GCM or ChaCha20 only nmap --script ssl-enum-ciphers -p 443 legacy.example.com - 2.
Último recurso para um servidor legado impossível de manter: native-tls
Um cliente dedicado compilado com a feature native-tls do reqwest usa a biblioteca TLS da plataforma (o OpenSSL no Linux, que precisa dos cabeçalhos de desenvolvimento para compilar), e essa biblioteca ainda pode permitir suites mais antigas, conforme a política do sistema. Restrinja esse cliente ao endpoint legado; a configuração fraca do servidor continua sendo um risco.
toml # A legacy server you cannot upgrade: build a separate client on the OS TLS library # (OpenSSL on Linux), which still implements older suites. Cargo.toml: reqwest = { version = "=0.13.5", default-features = false, features = ["native-tls", "blocking"] } - 3.
TLS mútuo: apresentar um certificado de cliente
reqwest::Identity::from_pem com um PEM que contém o certificado e a chave privada; a identidade resultante é definida no builder.
rust // Mutual TLS with rustls: present a client certificate (PEM with certificate + private key) let identity = reqwest::Identity::from_pem(&std::fs::read("client-cert-and-key.pem")?)?; let client = reqwest::Client::builder().identity(identity).build()?;