Message d’erreur
curl: (60) SSL certificate problem: self-signed certificate
Également affiché sous la forme
- curl: (60) SSL certificate problem: self signed certificate
- curl: (60) SSL certificate OpenSSL verify result: self-signed certificate (18)
OpenSSL 3.0 et les versions ultérieures affichent « self-signed certificate » ; OpenSSL 1.1.1 affiche « self signed certificate ». Les versions plus récentes de curl (8.22.0 dans notre test) le formulent « SSL certificate OpenSSL verify result: self-signed certificate (18) ». Ne le confondez pas avec « self-signed certificate in certificate chain », où une chaîne d’AC existe et se termine par une racine non approuvée.
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)
Ce que cela signifie
Le serveur a présenté un seul certificat, signé par sa propre clé (l’émetteur est identique au sujet), et curl n’a pas ce certificat exact dans son magasin de confiance. Il n’y a derrière lui aucune AC que curl pourrait rechercher, si bien que la vérification s’arrête à la profondeur 0. C’est normal pour les serveurs de développement et les équipements, et cela ne se corrige jamais en installant un certificat intermédiaire.
Pourquoi cela se produit
Un serveur de développement ou de test avec un certificat généré
fréquenteLes serveurs HTTPS locaux, les environnements docker-compose et les jeux de test génèrent souvent un certificat auto-signé au démarrage (par exemple avec openssl req -x509). Chaque régénération produit un nouveau certificat : une copie approuvée hier peut donc ne plus correspondre aujourd’hui.
Un appareil ou un produit utilise encore son certificat d’usine
fréquenteLes routeurs, les boîtiers NAS, les imprimantes, les interfaces iDRAC/iLO, ainsi que les installations de Proxmox, Jenkins ou Elasticsearch sont livrés avec un certificat auto-signé jusqu’à ce que quelqu’un installe un vrai certificat.
Un proxy ou un ingress sert son certificat par défaut
occasionnelleQuand aucun certificat ne correspond au nom demandé, ingress-nginx sert « Kubernetes Ingress Controller Fake Certificate » et Traefik sert « TRAEFIK DEFAULT CERT », tous deux auto-signés. Le vrai problème relève alors du routage ou du SNI, pas de la confiance.
Le serveur pointe vers le mauvais fichier
rareUne configuration qui référence un certificat auto-signé temporaire (snakeoil.pem sous Debian, localhost.crt fourni par un paquet) au lieu du certificat émis produit cette erreur alors même qu’un vrai certificat existe sur le disque.
Comment corriger l’erreur
- 1.
Faire confiance exactement à ce certificat, après l’avoir vérifié
Pour un seul point de terminaison interne, enregistrez le certificat, confirmez son empreinte SHA-256 par un canal de confiance (la console de l’appareil, l’administrateur qui l’a créé) et passez-le avec --cacert. curl accepte alors ce certificat et aucun autre pour cet appel.
bash # Fetch the certificate once, compare its fingerprint out of band, then trust exactly that file openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \ | openssl x509 -out api.example.com.pem openssl x509 -in api.example.com.pem -noout -fingerprint -sha256 curl --cacert api.example.com.pem https://api.example.com:8443/ - 2.
Développement : émettre les certificats depuis une AC locale
Une AC locale (mkcert, step-ca ou une racine faite maison) vous permet d’approuver une racine une seule fois et d’émettre des certificats pour autant d’hôtes de développement que vous le souhaitez. Les certificats ne sont plus auto-signés : l’erreur disparaît donc partout où la racine est installée.
bash # mkcert creates a local CA, installs it into the system and browser stores, # and issues certificates signed by it (no longer self-signed) mkcert -install mkcert api.example.test localhost 127.0.0.1 - 3.
Hôtes publics : installer un certificat émis par une AC publique
Tout ce qui est accessible à d’autres personnes ou à des clients tiers devrait présenter un certificat émis par une AC reconnue publiquement ; les clients ACME tels que certbot, lego ou Caddy en obtiennent un et le renouvellent automatiquement.
bash # Public names: get a certificate from a public CA, e.g. with certbot (ACME) sudo certbot certonly --nginx -d api.example.com - 4.
Diagnostic temporaire : tester le service avec la vérification désactivée
-k fait ignorer à curl les contrôles de certificat, si bien qu’un code 200 confirme que seule la confiance fait défaut. Ne le conservez pas : un certificat auto-signé accepté sans contrôle peut être remplacé à tout moment par celui d’un attaquant, et curl ne s’en apercevrait pas.
bash # Diagnostic only: confirms the service answers when certificate checks are skipped curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com:8443/
Erreurs associées
curl: (60) SSL certificate problem: self-signed certificate in certificate chaincurl (OpenSSL backend)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)verify error:num=18:self-signed certificateOpenSSL CLI (openssl s_client / openssl verify)code: 'DEPTH_ZERO_SELF_SIGNED_CERT'Node.js tls / https / fetch