Mensaje de error
received fatal alert: HandshakeFailure
reqwest lo imprime al final de su cadena de errores; ureq, como «io: received fatal alert: HandshakeFailure». Contra un servidor que solo admite TLS 1.0 (tls-v1-0.badssl.com), nuestro cliente rustls recibió esta misma alerta. Las demás alertas aparecen con sus propios nombres de rustls después de «received fatal alert: ».
rustls (via reqwest, ureq, tonic) — rustls::Error::AlertReceived(HandshakeFailure)
Qué significa
El servidor respondió al ClientHello de rustls con la alerta TLS 40 (handshake_failure). rustls implementa a propósito solo TLS moderno: TLS 1.2 y 1.3 con intercambio de claves ECDHE y cifrados AEAD. Los servidores que exigen intercambio de claves RSA, conjuntos de cifrado CBC, TLS 1.0/1.1 o un certificado de cliente lo rechazan de esta forma.
Por qué ocurre
Ningún conjunto de cifrado implementado por rustls
frecuenteLos servidores heredados limitados a conjuntos de cifrado CBC-SHA, 3DES o con intercambio de claves RSA no tienen nada en común con rustls.
El servidor solo habla TLS 1.0 o 1.1
frecuenterustls no implementa las versiones de TLS anteriores a la 1.2.
El servidor exige un certificado de cliente
ocasionalEn TLS 1.2, los endpoints con TLS mutuo responden con handshake_failure a un cliente sin certificado.
Cómo solucionarlo
- 1.
Comprobar qué ofrece el servidor
Si no ofrece ningún conjunto de cifrado ECDHE + AEAD, hay que modernizar el servidor.
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 un servidor heredado que no se puede mantener: native-tls
Un cliente dedicado compilado con la característica native-tls de reqwest usa la biblioteca TLS de la plataforma (OpenSSL en Linux, que necesita sus cabeceras de desarrollo para compilar), y esa biblioteca aún puede permitir conjuntos de cifrado más antiguos, según la política del sistema. Limítalo al endpoint heredado; la configuración débil del servidor sigue siendo un riesgo.
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 mutuo: presentar un certificado de cliente
reqwest::Identity::from_pem con un PEM que contiene el certificado y la clave privada; la identidad resultante se asigna al 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()?;