Certificat HTTPS valide ici, refusé ailleurs : diagnostiquer TLS avec OpenSSL et curl
Le certificat est annoncé comme valide sur le serveur, votre navigateur l’accepte, mais un client API, un vieux téléphone ou une sonde externe le refuse. Ce n’est pas forcément un bug « aléatoire » de TLS. Le plus souvent, on ne teste simplement pas le même chemin : autre adresse IP, autre terminaison TLS, autre magasin de confiance, chaîne intermédiaire incomplète ou nom d’hôte différent.
Voici une méthode reproductible pour isoler le problème sans masquer les erreurs avec une option permissive.
Commencer par séparer les couches
Un « HTTPS fonctionne » mélange plusieurs contrôles indépendants :
- la connexion TCP ou QUIC atteint bien le bon équipement ;
- le serveur reçoit le bon SNI et sélectionne le bon vhost ;
- le certificat couvre le nom demandé dans son extension Subject Alternative Name (SAN) ;
- ses dates de validité sont acceptables pour l’horloge du client ;
- la chaîne présentée remonte jusqu’à une autorité racine approuvée localement ;
- le proxy, le CDN ou le load balancer sert bien la version attendue du certificat.
Le navigateur peut en plus avoir mis en cache un certificat intermédiaire. Une machine « propre » ou un conteneur minimal peut alors révéler une chaîne incomplète que votre poste habituel cachait.
Faire un vrai test de base avec OpenSSL
openssl s_client \
-connect example.com:443 \
-servername example.com \
-verify_hostname example.com \
-verify_return_error \
-showcerts \
</dev/null
Chaque option a son importance :
-connectchoisit l’hôte et le port réellement contactés ;-servernameenvoie le SNI. Sans lui, une IP mutualisée peut retourner le certificat du vhost par défaut ;-verify_hostnamevérifie que le certificat correspond bien au nom demandé. La validation de la chaîne seule ne suffit pas ;-verify_return_errorévite ques_clientcontinue tranquillement après une erreur de vérification ;-showcertsaffiche les certificats réellement envoyés par le serveur. Ce n’est pas, à lui seul, une preuve que la chaîne est valide.
Un simple message CONNECTED prouve seulement qu’une connexion a été ouverte. Le résultat intéressant se trouve dans les erreurs de vérification et dans la ligne finale Verify return code. Le test utilise le magasin de confiance local ; deux systèmes peuvent donc aboutir à des conclusions différentes si leurs autorités racines ou leur horloge ne sont pas à jour.
Inspecter le certificat feuille sans se noyer dans la sortie
openssl s_client \
-connect example.com:443 \
-servername example.com \
</dev/null 2>/dev/null |
openssl x509 \
-noout \
-subject \
-issuer \
-serial \
-dates \
-ext subjectAltName
Cette commande extrait le premier certificat présenté, normalement le certificat feuille. Vérifiez quatre choses : le sujet, l’émetteur, les dates et surtout les SAN. Le champ Common Name historique ne doit pas remplacer ce dernier contrôle.
Pour une alerte automatisée sept jours avant expiration :
openssl s_client \
-connect example.com:443 \
-servername example.com \
</dev/null 2>/dev/null |
openssl x509 -noout -checkend 604800
-checkend renvoie un code de sortie nul si le certificat reste valable pendant le nombre de secondes demandé, et un code non nul sinon. C’est pratique dans une sonde, à condition de tester depuis l’extérieur et de surveiller le code de sortie plutôt que le texte affiché.
Vérifier la chaîne réellement servie
En production, le serveur présente généralement le certificat feuille puis le ou les certificats intermédiaires nécessaires. La racine de confiance n’a normalement pas besoin d’être envoyée : elle doit déjà appartenir au magasin du client.
Une chaîne incomplète produit le scénario classique « ça marche chez moi ». Un navigateur ayant déjà rencontré l’intermédiaire peut reconstruire le chemin, alors qu’un conteneur neuf échoue. À l’inverse, une chaîne alternative peut fonctionner sur les clients récents et coincer sur un appareil ancien dont le magasin de racines n’a pas été actualisé.
- Comptez ce que
-showcertsaffiche : feuille seule ou feuille plus intermédiaires. - Relancez le test depuis un système propre ou une sonde extérieure.
- Si nécessaire, imposez un magasin connu avec
-CAfileou-CApathpour comparer les résultats. - Ne corrigez pas le symptôme avec
curl -k: cette option désactive précisément le contrôle qui vous protège.
Tester une IP précise sans casser le SNI
Après une migration DNS, derrière plusieurs nœuds ou avec un CDN, le domaine peut mener vers plusieurs adresses. Tester uniquement https://203.0.113.10 change le nom demandé et peut sélectionner le mauvais certificat. Utilisez plutôt :
curl -Iv \
--resolve example.com:443:203.0.113.10 \
https://example.com/
--resolve force l’adresse pour ce couple hôte-port tout en conservant le nom example.com dans l’URL, le SNI et la requête HTTP. C’est le bon moyen de vérifier chaque nœud avant une bascule DNS, ou de découvrir qu’un seul serveur du pool sert encore l’ancien certificat.
Commencez par relever les enregistrements A et AAAA, puis répétez le test pour chaque adresse. N’oubliez pas IPv6 : un site peut être parfait en IPv4 et cassé en IPv6, ou l’inverse. Distinguez aussi l’origine du CDN de ses nœuds publics ; ce ne sont pas les mêmes terminaisons TLS.
Lire les symptômes sans tirer de conclusion trop vite
- Certificat d’un autre domaine : SNI absent, vhost par défaut ou configuration du proxy incorrecte.
- Bon certificat sur certains clients seulement : intermédiaire manquant, racine absente du magasin local, horloge fausse ou chaîne alternative peu compatible.
- Ancien certificat sur une seule IP : nœud oublié, service non rechargé ou terminaison TLS différente de celle que vous avez renouvelée.
- Nom de domaine valide mais accès direct par IP refusé : comportement normal si l’adresse IP ne figure pas dans les SAN.
- Absence d’OCSP stapling : information utile avec l’option
-status, mais pas une preuve automatique de révocation ni la cause universelle d’un refus.
Après le renouvellement, contrôler ce qui est vraiment en ligne
Obtenir un nouveau fichier avec ACME n’est que la moitié du travail. Il faut encore que le bon service le charge. Une procédure robuste vérifie donc, après renouvellement :
- le numéro de série et les dates vus depuis Internet ;
- le nom d’hôte avec
-verify_hostname; - la chaîne complète sur un client propre ;
- chaque adresse publique et chaque terminaison TLS ;
- une marge d’alerte suffisante avant la prochaine expiration.
Et un rappel qui évite une vraie catastrophe : le certificat public peut être inspecté, mais la clé privée ne doit jamais être collée dans un ticket, un chat ou une commande partagée.
En bref
Pour diagnostiquer TLS proprement, testez le bon nom, le bon SNI, le bon magasin de confiance et chaque point de terminaison. OpenSSL explique ce que le serveur présente ; curl vérifie le comportement HTTP d’une cible précise. Ensemble, ils transforment un vague « ça marche chez moi » en cause mesurable.
Si le problème se cache dans un proxy, une migration ou une configuration de serveur, vous pouvez aussi consulter les services proposés par FuretSplick pour voir quel accompagnement correspond à votre situation.
