Mensaje de error
invalid peer certificate: UnknownIssuer
También se muestra como
- InvalidCertificate(UnknownIssuer)
reqwest lo imprime al final de su cadena de causas: «error sending request for url (…): client error (Connect): invalid peer certificate: UnknownIssuer»; la salida Debug muestra InvalidCertificate(UnknownIssuer). ureq imprime «io: invalid peer certificate: UnknownIssuer». Los binarios nativos basados en rustls (pnpm 12, muchas CLI) muestran el mismo texto.
rustls (via reqwest, ureq, hyper-rustls, tonic) — rustls::Error::InvalidCertificate(CertificateError::UnknownIssuer)
Qué significa
rustls no pudo encadenar el certificado del servidor con ninguna de las anclas de confianza configuradas. UnknownIssuer es el único código de rustls para cualquier fallo en la construcción de la ruta: una CA privada o de un proxy, un certificado intermedio que falta o un certificado autofirmado. Qué raíces se consideran de confianza depende de cómo se compiló el crate: el verificador de la plataforma (almacén del sistema operativo), rustls-native-certs (raíces del sistema operativo cargadas al arrancar) o webpki-roots (la lista de Mozilla incluida en la compilación).
Por qué ocurre
Una CA corporativa o privada
frecuenteLa cadena del servidor termina en una raíz que no está entre las anclas configuradas, algo típico de los servicios internos y de los proxies que inspeccionan TLS.
El cliente solo confía en las raíces públicas incluidas en la compilación
frecuenteLos crates compilados con webpki-roots ignoran por completo el almacén del sistema operativo, así que una raíz instalada por el departamento de TI nunca se aplica. El verificador de la plataforma, que reqwest 0.13 usa por defecto, sí usa el almacén del sistema operativo (como confirmó la reproducción tras ejecutar update-ca-certificates).
El servidor no envía su certificado intermedio
ocasionalrustls no descarga los certificados intermedios que faltan; un servidor que solo envía el certificado hoja falla con UnknownIssuer aunque la raíz sea de confianza.
Un certificado de servidor autofirmado
ocasionalrustls también clasifica los certificados autofirmados como UnknownIssuer; configura ese cliente para que confíe en el certificado como raíz, o sustitúyelo.
Cómo solucionarlo
- 1.
Añadir la raíz al cliente
ClientBuilder::add_root_certificate añade un ancla y mantiene la verificación completa (nombres, fechas).
rust // Trust a private root for this client (in addition to the default roots) let pem = std::fs::read("corp-root-ca.pem")?; let client = reqwest::Client::builder() .add_root_certificate(reqwest::Certificate::from_pem(&pem)?) .build()?; - 2.
Instalar la raíz en el almacén del sistema operativo
Con el verificador de la plataforma (el predeterminado de reqwest 0.13), las raíces del almacén del sistema operativo son de confianza; en Linux basta con update-ca-certificates.
bash # reqwest 0.13 verifies with the platform verifier: install the root in the OS store sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates - 3.
Comprobar qué fuente de raíces se incluye en la compilación
cargo tree muestra si se usa webpki-roots o rustls-native-certs; cambia las características (features) activadas si debe aplicarse el almacén del sistema operativo.
bash # Which root source is compiled into this binary? (a crate that is absent reports no match) cargo tree -e features -i rustls-platform-verifier # OS verifier (reqwest 0.13 default) cargo tree -e features -i rustls-native-certs # OS roots loaded at start-up cargo tree -e features -i webpki-roots # Mozilla roots compiled in, OS store ignored - 4.
Administradores del servidor: enviar el certificado intermedio
Si en el handshake solo hay un certificado y su emisor es un intermedio, la configuración del servidor está incompleta.
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:'
Errores relacionados
invalid peer certificate: certificate expired: verification timerustls 0.23 (via reqwest, ureq, hyper-rustls)invalid peer certificate: certificate not valid for name "api.example.com"; cer…rustls 0.23 (via reqwest, ureq, hyper-rustls)Error: ERR_PNPM_RESOLVING_NPM_RESOLVER_NETWORK_ERRORpnpm 12 (native binary, rustls)x509: certificate signed by unknown authorityGo crypto/x509