Retour

2026/10/23

Le 20 octobre 2026, il a été rendu public que les clés privées de huit autorités de certification (CA) intermédiaires exploitées par eMudhra, une CA indienne, peuvent être récupérées par n’importe qui. Les navigateurs ont bloqué les certificats le jour même où le problème a été signalé. En revanche, de nombreuses applications Java leur font encore confiance aujourd’hui, et continueront de le faire tant que personne n’aura mis à jour le JDK ou modifié son truststore.

Le 21 octobre 2026, BellSoft a publié des résultats de tests montrant que de nombreux runtimes Java acceptent encore ces certificats. Cet article résume leurs conclusions, que nous avons vérifiées par nos propres tests, et explique pourquoi Java est concerné alors que les navigateurs ne le sont pas, comment vérifier vos systèmes et que faire.

À retenir

  • Huit clés de CA intermédiaires d’eMudhra sont compromises. Quiconque en détient une peut émettre un certificat pour n’importe quel nom d’hôte, et un client qui fait confiance à la chaîne l’acceptera.
  • Les navigateurs les bloquent, mais Java utilise son propre truststore et, par défaut, ne vérifie ni la révocation ni Certificate Transparency.
  • Des builds du JDK de plusieurs fournisseurs font encore confiance à tout ou partie des chaînes concernées, y compris dans des images de conteneur.
  • En attendant que votre fournisseur livre un JDK corrigé, supprimez les deux racines concernées du truststore, après avoir testé. La vérification de la révocation est une seconde option.

Ce qui s’est passé

eMudhra a mal généré les clés privées de huit de ses certificats de CA intermédiaire, si bien que n’importe qui peut les retrouver à partir des certificats publics. C’est possible depuis l’émission des intermédiaires, en avril 2025.

Le 17 octobre 2026, la personne à l’origine du signalement a prouvé le problème en signant le message « We have a problem here » avec chacune des huit clés et en envoyant les signatures aux programmes de racines des navigateurs. Les détails ont été rendus publics le 20 octobre.

  • Six intermédiaires émettent des certificats TLS : les CA TLS DV, OV et EV d’eMudhra, générations G3B et G3C.
  • Deux intermédiaires émettent des certificats de signature de code.
  • Chaque intermédiaire existe en deux exemplaires : signé par une racine emSign d’eMudhra, et contresigné (cross-sign) par la racine AAA Certificate Services de Sectigo. Dans un truststore du JDK, les chaînes aboutissent à l’une de deux racines : emSign ECC Root CA - G3 (via une contresignature) ou AAA Certificate Services.

Firefox et Chrome bloquent les intermédiaires depuis le 17 octobre, Apple depuis le 19 octobre et Microsoft depuis le 20 octobre. eMudhra a révoqué les huit les 18 et 19 octobre avec le motif CA_COMPROMISE. Les distributions Linux ont publié des paquets de certificats de CA mis à jour.

Quel est l’impact

Quiconque détient l’une de ces clés peut créer un certificat pour n’importe quel nom d’hôte, par exemple celui de votre banque, de votre fournisseur cloud ou de votre propre passerelle d’API. Un client qui fait confiance à la chaîne l’acceptera. S’il dispose en plus d’un moyen d’intercepter le trafic, par exemple un réseau compromis ou un enregistrement DNS modifié, un attaquant pourrait :

  • lire et modifier le trafic entre une application Java et les services qu’elle appelle, y compris les mots de passe, clés d’API et jetons ;
  • usurper l’identité de dépôts de paquets, de serveurs de mise à jour ou d’API de partenaires ;
  • grâce aux deux intermédiaires de signature de code, signer du code qui semble provenir d’un éditeur de confiance.

Les intermédiaires ne sont jamais apparus dans les journaux Certificate Transparency (CT) : les navigateurs qui imposent CT ne pouvaient donc pas être attaqués par leur biais. On ne sait pas encore si les clés ont été utilisées contre des clients qui ne vérifient pas CT. Java fait partie de ces clients.

Pourquoi Java fait encore confiance à ces certificats

Mozilla, Google, Apple et Microsoft ont diffusé le blocage par leurs propres canaux, comme OneCRL, CRLite et CRLSets. L’implémentation TLS par défaut du JDK n’en lit aucun. Trois réglages par défaut laissent Java exposé :

  • Son propre truststore. Sauf si une application définit javax.net.ssl.trustStore, Java fait confiance aux racines de $JAVA_HOME/lib/security/jssecacerts si ce fichier existe, et sinon à celles de $JAVA_HOME/lib/security/cacerts. Un cacerts fourni par le fournisseur ne reçoit ni les listes de blocage des navigateurs ni les mises à jour de CA du système d’exploitation. Il ne change que lorsqu’un administrateur le modifie ou qu’une mise à jour du JDK le remplace.
  • Pas de vérification de la révocation. Java ne vérifie pas la révocation sauf si vous l’activez (com.sun.net.ssl.checkRevocation vaut false par défaut) : la révocation par la CA est donc invisible pour une configuration par défaut.
  • Pas de Certificate Transparency. Le JDK n’impose pas CT, donc la protection dont bénéficiaient les utilisateurs de navigateurs ne s’applique pas.

La page de divulgation liste douze hôtes de test, un pour chaque combinaison d’intermédiaire et de racine. BellSoft les a testés sous Linux le 21 octobre, et nous avons refait le test le 23 octobre :

Runtime testéHôtes de test acceptés
Liberica JDK 21.0.1012 sur 12
Liberica JDK 8u504 (image de conteneur)12 sur 12
Liberica JDK 21.0.12.1 (image de conteneur)12 sur 12
Eclipse Temurin 25.0.4.16 sur 12 (racine eMudhra uniquement)
Eclipse Temurin 21.0.12.1 (image de conteneur, notre test)6 sur 12 (racine eMudhra uniquement)
Arch Linux OpenJDK 27 (magasin de CA du système)6 sur 12 (racine eMudhra uniquement)

La différence tient à la racine Sectigo. Mozilla avait déjà retiré AAA Certificate Services, et les truststores de Temurin et d’Arch Linux sont construits à partir de la liste de Mozilla : seul le chemin eMudhra reste ouvert. Le truststore de Liberica JDK contient encore cette racine, donc les deux chemins sont ouverts.

Quels systèmes vérifier

  • Les JDK autonomes décompressés depuis une archive du fournisseur ou installés avec un installeur du fournisseur. Ils utilisent leur propre cacerts.
  • Les images de conteneur qui embarquent un JDK. Dans les images testées par BellSoft, la mise à jour du paquet ca-certificates du système d’exploitation n’a pas modifié le cacerts du JDK. Récupérer une image de base plus récente n’a pas aidé non plus : l’image Liberica du 21 octobre testée faisait encore confiance aux douze hôtes de test.
  • Les applications dotées de leur propre truststore, défini avec javax.net.ssl.trustStore, dans la configuration d’un serveur d’applications ou dans l’application elle-même. Vérifiez s’ils contiennent les deux racines.
  • OpenJDK empaqueté par la distribution. Vérifiez vers quoi pointe cacerts. S’il renvoie au magasin de CA du système (sous Arch Linux, c’est un lien symbolique vers /etc/ca-certificates/extracted/java-cacerts.jks), la mise à jour de ca-certificates de la distribution corrige le problème. La page de divulgation indique les versions de paquets corrigées.

Comment vérifier votre JDK

Commencez par rechercher les deux racines dans le truststore. Les noms d’alias varient selon les fournisseurs (Liberica JDK utilise emsigneccrootcag3 [jdk], Temurin utilise cn_emsign_ecc_root_ca__g3,...) : recherchez donc par sujet du certificat. Il existe plusieurs autres racines emSign ; seule emSign ECC Root CA - G3 est concernée. Sur JDK 9 et versions ultérieures :

keytool -list -v -cacerts -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'

Le keytool de Java 8 n’a pas d’option -cacerts, et son truststore se trouve sous jre/ :

keytool -list -v -keystore "$JAVA_HOME/jre/lib/security/cacerts" -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'

Chaque correspondance affiche le nom d’alias suivi du sujet du certificat. Notez les noms d’alias : vous en aurez besoin pour la correction.

Testez ensuite de vraies connexions. Ce petit programme se connecte aux douze hôtes de test et fonctionne sur Java 8 et toutes les versions ultérieures :

import java.net.URI;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
public class Check {
    public static void main(String[] args) {
        for (String level : new String[]{"dv", "ov", "ev"})
            for (String gen : new String[]{"g3b", "g3c"})
                for (String via : new String[]{"", "-aaa"}) {
                    String host = level + "-" + gen + via + "-emudhra.we-have-a-problem.com";
                    try {
                        HttpsURLConnection c = (HttpsURLConnection) URI.create("https://" + host).toURL().openConnection();
                        c.setConnectTimeout(10000);
                        c.setReadTimeout(10000);
                        c.connect();
                        c.disconnect();
                        System.out.println("TRUSTED       " + host);
                    } catch (SSLHandshakeException e) {
                        System.out.println("TLS_REJECTED  " + host);
                    } catch (Exception e) {
                        System.out.println("ERROR         " + host + " (" + e + ")");
                    }
                }
    }
}

Sur JDK 11 ou ultérieur, exécutez-le avec java Check.java. Sur Java 8, ou là où seul un JRE est installé, compilez-le d’abord avec javac Check.java (sur une machine disposant d’un JDK si nécessaire), puis lancez java Check. Une ligne TRUSTED signifie que ce JDK accepte une intermédiaire compromise. ERROR signifie que l’hôte n’a pas pu être joint, ce qui ne prouve rien dans un sens ni dans l’autre. Lancez la vérification avec le même JDK et les mêmes paramètres de truststore que votre application, y compris dans vos conteneurs.

Comment corriger le problème

1. Supprimer les deux racines (recommandé en attendant un JDK corrigé)

Ce sont les deux mêmes racines que la page de divulgation demande aux utilisateurs de Linux et de macOS de ne plus approuver. Exécutez les commandes avec l’utilisateur propriétaire du JDK, en utilisant les noms d’alias trouvés lors de la vérification. Par exemple, sur Liberica JDK :

keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"

Sur Java 8, remplacez -cacerts par -keystore "$JAVA_HOME/jre/lib/security/cacerts". Si votre truststore ne contient qu’une des deux racines, comme celui de Temurin, supprimez uniquement celle-ci.

Si vous ne pouvez pas modifier l’installation du JDK, modifiez une copie et indiquez-la à la JVM :

cp "$JAVA_HOME/lib/security/cacerts" ./trimmed-cacerts
keytool -delete -keystore ./trimmed-cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -keystore ./trimmed-cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
java -Djavax.net.ssl.trustStore=./trimmed-cacerts -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar

Lors de nos tests, les deux méthodes ont conduit Liberica JDK 8 et 21 à rejeter les douze hôtes de test, tandis que des sites ordinaires comme sectigo.com et github.com restaient accessibles.

Pour les images de conteneur, supprimez les racines au moment du build afin que chaque nouvelle image soit corrigée :

FROM bellsoft/liberica-runtime-container:jdk-21-musl
RUN keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]" \
 && keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"

Les images distroless et celles qui ne tournent pas en root nécessitent deux modifications : elles n’ont pas de shell, donc utilisez la forme exec de RUN avec une commande par ligne ; et elles s’exécutent avec un utilisateur non privilégié, donc passez à USER root pour la modification, puis revenez ensuite à l’utilisateur habituel de l’image.

Astuce : Supprimer une racine a une portée plus large que bloquer huit intermédiaires. Un serveur légitime dont la chaîne aboutit uniquement à l’une de ces racines cessera de fonctionner. Testez les services appelés par votre application avant de déployer ce changement, et relancez la vérification après chaque mise à jour du JDK, car une mise à jour ou une réinstallation peut restaurer le cacerts d’origine.

2. Activer la vérification de la révocation (facultatif)

eMudhra a révoqué les huit intermédiaires : une JVM qui vérifie la révocation les rejette donc sans aucune modification du truststore. Activez les points de distribution de CRL et OCSP :

echo 'ocsp.enable=true' > revocation.security
java -Dcom.sun.net.ssl.checkRevocation=true \
     -Dcom.sun.security.enableCRLDP=true \
     -Djava.security.properties=revocation.security \
     -jar app.jar

Lors de nos tests, cela a rejeté les douze hôtes de test sur Liberica JDK 8 et 21 ainsi que sur Temurin 21. Cela change toutefois la manière dont chaque certificat est validé. La JVM effectue des requêtes OCSP ou CRL pendant la validation du chemin, et un handshake peut échouer lorsque le statut de révocation ne peut pas être déterminé. Avant de l’activer globalement, vérifiez si les répondeurs sont joignables depuis vos serveurs, quelle latence ils ajoutent et comment les échecs se comportent. Utilisez cette option si vous fonctionnez déjà avec la vérification de la révocation, ou en complément de la suppression des racines.

3. Mettre à jour le JDK dès que des builds corrigés sont disponibles

BellSoft a indiqué préparer des mises à jour de Liberica JDK qui suppriment ces racines. Suivez les bulletins de sécurité de votre propre fournisseur de JDK. Lorsque la mise à jour sort, lisez ses notes de version pour confirmer qu’elle couvre les certificats eMudhra, installez-la, reconstruisez vos images de conteneur et relancez la vérification. Un numéro de version plus récent ne suffit pas à le prouver.

Après la correction : évaluez votre exposition

Les clés étaient récupérables depuis environ dix-huit mois : la correction ferme la porte, mais ne vous dit pas si quelqu’un l’a utilisée. Pour les systèmes qui envoient des identifiants ou des données sensibles, recherchez dans les journaux d’inspection TLS, de proxy et des endpoints des certificats émis par les huit intermédiaires d’eMudhra. Si vous trouvez quoi que ce soit de suspect, renouvelez les identifiants concernés.

À plus long terme, traitez les truststores comme des dépendances : sachez où se trouve chacun d’eux, qui le met à jour et en combien de temps une modification arrive en production. Cet incident montre qu’une mise à jour des navigateurs ne suffit pas lorsque vos serveurs utilisent leur propre copie de la liste de confiance.

Besoin d’aide ? LOGIQ assure le support d’OpenJDK et de Linux, y compris l’application des correctifs de sécurité. Si vous souhaitez de l’aide pour repérer tous les JDK et truststores de votre environnement ou pour déployer une correction en toute sécurité, contactez-nous.

Pour aller plus loin