Mensagem de erro
invalid peer certificate: UnknownIssuer
Também aparece como
- InvalidCertificate(UnknownIssuer)
O reqwest o imprime no fim da cadeia de causas: “error sending request for url (…): client error (Connect): invalid peer certificate: UnknownIssuer”; a saída Debug mostra InvalidCertificate(UnknownIssuer). O ureq imprime “io: invalid peer certificate: UnknownIssuer”. Binários nativos baseados no rustls (pnpm 12, muitas CLIs) mostram o mesmo texto.
rustls (via reqwest, ureq, hyper-rustls, tonic) — rustls::Error::InvalidCertificate(CertificateError::UnknownIssuer)
O que significa
O rustls não conseguiu encadear o certificado do servidor a nenhuma das âncoras de confiança com que foi configurado. UnknownIssuer é o código único do rustls para qualquer falha na construção do caminho: uma CA privada ou de proxy, um intermediário ausente ou um certificado autoassinado. Quais raízes contam como confiáveis depende de como o crate foi compilado: o verificador da plataforma (repositório do sistema operacional), o rustls-native-certs (raízes do sistema carregadas na inicialização) ou o webpki-roots (a lista da Mozilla compilada no binário).
Por que acontece
Uma CA da empresa ou privada
comumA cadeia do servidor termina em uma raiz que não está entre as âncoras configuradas, algo típico de serviços internos e de proxies com inspeção de TLS.
O cliente confia só nas raízes públicas compiladas no binário
comumCrates compilados com o webpki-roots ignoram completamente o repositório do sistema operacional, então uma raiz instalada pela TI nunca é aplicada. Já o verificador da plataforma, padrão do reqwest 0.13, usa o repositório do sistema (como a reprodução confirmou depois de rodar update-ca-certificates).
O servidor não envia o intermediário
ocasionalO rustls não busca intermediários ausentes; um servidor que envia só o certificado folha falha com UnknownIssuer mesmo que a raiz seja confiável.
Um certificado de servidor autoassinado
ocasionalO rustls também relata certificados autoassinados como UnknownIssuer; confie no certificado como raiz nesse cliente ou substitua-o.
Como corrigir
- 1.
Adicionar a raiz ao cliente
O ClientBuilder::add_root_certificate adiciona uma âncora e mantém a verificação completa (nomes, datas).
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 a raiz no repositório do sistema operacional
Com o verificador da plataforma (o padrão do reqwest 0.13), as raízes do repositório do sistema operacional são confiáveis; no Linux, basta 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.
Verificar qual fonte de raízes está compilada
O cargo tree mostra se o webpki-roots ou o rustls-native-certs está em uso; troque as features se o repositório do sistema operacional precisar valer.
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.
Donos do servidor: enviar o intermediário
Se o handshake traz um único certificado e o emissor dele é um intermediário, a configuração do 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:'
Erros 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