Message d’erreur
curl: (60) SSL certificate problem: self-signed certificate in certificate chain
Également affiché sous la forme
- curl: (60) SSL certificate problem: self signed certificate in certificate chain
- curl: (60) SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)
OpenSSL 3.0 et les versions ultérieures affichent « self-signed » ; OpenSSL 1.1.1 affiche « self signed » sans trait d’union, si bien que les deux graphies apparaissent dans les journaux et les résultats de recherche. Les versions plus récentes de curl (8.22.0 dans notre test) le formulent « SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19) ». Les builds de curl utilisant Schannel sous Windows signalent ce cas par « SEC_E_UNTRUSTED_ROOT ».
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN (19)
Ce que cela signifie
curl a remonté la chaîne envoyée par le serveur jusqu’à un certificat racine auto-signé, et cette racine ne figure pas dans le fichier d’AC de curl. Contrairement à « unable to get local issuer certificate », la chaîne est complète : curl voit la racine, il n’a simplement aucune raison de lui faire confiance. En pratique, la racine appartient presque toujours à une AC d’entreprise ou à un proxy qui intercepte TLS.
Pourquoi cela se produit
Un proxy d’inspection TLS ou un antivirus re-signe les connexions
fréquenteZscaler, Netskope, Fortinet, Palo Alto et de nombreux antivirus terminent TLS et présentent des certificats émis par leur propre racine, qu’ils envoient dans la chaîne. Le navigateur fait confiance à cette racine via le système d’exploitation, mais curl dans WSL, Docker, Git Bash ou un runner de CI lit son propre fichier d’AC et la rejette. L’émetteur du certificat désigne l’éditeur du proxy ou votre entreprise, et non la véritable AC du site.
Le service utilise une racine privée et l’envoie dans la chaîne
fréquenteLes services internes, les ingress Kubernetes et les équipements utilisent souvent un certificat issu d’une racine d’entreprise ou faite maison, et incluent cette racine dans la chaîne servie. Envoyer la racine ne suffit pas à la faire approuver : une ancre de confiance doit déjà se trouver sur le client.
La racine privée est installée dans un autre magasin
occasionnelleLa racine a été ajoutée au magasin de certificats Windows, au trousseau macOS ou au cacerts de Java, mais ce curl lit un fichier d’AC OpenSSL tel que /etc/ssl/certs/ca-certificates.crt ou la copie fournie avec Git for Windows, Homebrew ou conda.
Le magasin de certificats racines publics du client est obsolète
rarePlus rarement, un serveur envoie une racine publique plus récente qu’un client ancien, jamais mis à jour, ne possède pas. Mettre à jour le paquet ca-certificates corrige le problème ; si la racine est réellement publique, les autres machines vérifieront le site sans difficulté.
Comment corriger l’erreur
- 1.
Déterminer à qui appartient la racine
Examinez le dernier certificat de la chaîne. Si le sujet est un proxy, un éditeur de solutions de sécurité ou le nom de votre entreprise, la correction consiste à faire confiance à cette racine sur cette machine. S’il s’agit d’un nom inattendu sur un réseau que vous ne contrôlez pas, arrêtez-vous : quelqu’un intercepte la connexion.
bash # Print the subject and issuer of every certificate the server (or the proxy) sends openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' # The last entry has s: == i: — that self-signed root is what curl does not trust. - 2.
Ajouter la racine de l’entreprise ou du proxy au magasin du système
Procurez-vous le certificat racine auprès de votre service informatique (ou exportez-le depuis le magasin de confiance d’une machine gérée) et installez-le dans le fichier d’AC du système d’exploitation qu’utilise curl. Les conteneurs en ont besoin au moment du build ; WSL en a besoin dans la distribution Linux, pas seulement dans Windows.
bash # Debian, Ubuntu, Alpine sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates # RHEL, Fedora, Amazon Linux sudo cp corp-root-ca.pem /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust - 3.
Faire confiance à la racine pour une seule commande ou un seul environnement
--cacert et CURL_CA_BUNDLE remplacent le fichier d’AC par défaut de curl : faites-les donc pointer vers un fichier qui contient à la fois les racines publiques et la racine privée lorsque le même processus communique aussi avec des sites publics.
bash curl --cacert corp-root-ca.pem https://api.example.com/ # Keep public roots too: build one bundle with both cat /etc/ssl/certs/ca-certificates.crt corp-root-ca.pem > /opt/certs/bundle.pem export CURL_CA_BUNDLE=/opt/certs/bundle.pem - 4.
Propriétaires de serveurs : ne pas compter sur l’envoi de la racine
Servez le certificat feuille et les certificats intermédiaires ; distribuez plutôt la racine privée aux clients via la gestion de configuration. Inclure la racine gaspille des octets et ne fait jamais d’une racine non approuvée une racine approuvée.
bash # Serve leaf + intermediates only; clients must already have the root cat api.example.com.crt intermediate.crt > fullchain.pem - 5.
Diagnostic temporaire : voir l’émetteur avec la vérification désactivée
-k désactive les contrôles de certificat pour que la sortie verbeuse puisse montrer le sujet et l’émetteur présentés par le serveur. Ne l’utilisez que pour identifier la racine. Laissé dans des scripts, -k permet à n’importe qui sur le chemin de lire et de modifier le trafic, y compris les jetons et les installateurs téléchargés.
bash # Diagnostic only: shows who issued the certificate even though curl distrusts it curl -sv -k -o /dev/null https://api.example.com/ 2>&1 | grep -E 'subject:|issuer:'
Erreurs associées
curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)curl: (60) SSL certificate problem: self-signed certificatecurl (OpenSSL backend)verify error:num=19:self-signed certificate in certificate chainOpenSSL CLI (openssl s_client / openssl verify)self-signed certificate in certificate chainNode.js tls / https / fetch[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certifi…Python ssl module (OpenSSL)