Repository navigation
SECURITY: jdk-21, jdk-25, jdk-27: distrust the compromised eMudhra intermediates (CVE-2026-111943) - #949
Merged
Conversation
…termediates (CVE-2026-111943) The private keys of eight eMudhra intermediate CAs were compromised (Mozilla bug 2083449). Each key is certified twice: by emSign Root TLS/CS CA - G3 with ECDSA, and cross-signed by Sectigo's AAA Certificate Services with RSA. OpenJDK and Temurin have shipped nothing, so each JDK is fixed at build time by the shared packages/jdk/cve-2026-111943.sh: - cacerts: remove emSign ECC Root CA - G3 (86A1ECBA...) and AAA Certificate Services (D7A7A0FB...), selected by SHA-256 fingerprint. Temurin's store has the first under a Mozilla-style alias and lacks the second; OpenJDK's own store has both (emsigneccrootcag3, comodoaaaca). - blocked.certs: append the 48 fingerprints in packages/ca-certificates/cve-2026-111943-blocked-sha256.txt, the one list for every trust store we patch. That is every encoding OpenJDK's BlockedCertsConverter would emit for the 16 certificates (as issued, NULL sig-alg params toggled, ECDSA s -> n-s), with malleability decided by the issuer's signature algorithm rather than the subject key. - JdkDistrust.java, run with the JDK being packaged, validates the compromised certificates against their issuers with PKIX before (they must validate) and after (they must fail as "Untrusted certificate"), checks an unrelated control chain still validates, and checks the rewritten cacerts reloads password-less with only the two roots gone. Any failure fails the build. Each JDK also gets a standalone test on the installed tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Warning Review limit reached
This review includes 11 billable files and costs up to $2.75.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 5 minutes for your next included review. View limit details
Comment |
jtnkminimal
approved these changes
Oct 20, 2026
This was referenced Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security: CVE-2026-111943 (eMudhra intermediate CA key compromise)
Mozilla bug 2083449. The private keys of eight eMudhra intermediate CAs (EC P-384) were compromised. Each key is certified twice, so 16 certificates are affected:
comodoaaaca.OpenJDK and Temurin have shipped nothing. Our three Temurin JDKs are therefore fixed at build time. Go's fix is golang/go@7f86f95, an SPKI blocklist. Java's equivalent is
lib/security/blocked.certs.What changes
packages/jdk/cve-2026-111943.shruns in each ofjdk-21,jdk-25andjdk-27, right after the image is copied into$OUTPUT_DIR:cacerts. It removes emSign ECC Root CA - G3 (
86A1ECBA…6BBE6B) and AAA Certificate Services (D7A7A0FB…699EF4). Entries are matched by SHA-256 fingerprint, not by alias. Temurin stores the emSign root ascn_emsign_ecc_root_ca__g3,o_emudhra_technologies_limited,ou_emsign_pki,c_in [jdk], OpenJDK asemsigneccrootcag3. The store is rewritten password-less with the JDK's ownKeyStoreAPI, which is whatkeytool -deletecalls. The rewritten store is then reloaded and must equal the original minus exactly those entries.blocked.certs. It appends the 48 fingerprints in
packages/ca-ce 8000 rtificates/cve-2026-111943-blocked-sha256.txt, de-duplicated and sorted. The script refuses to run if the header is notAlgorithm=SHA-256or if any line is not a 64-character uppercase hex fingerprint. It also fails if an existing entry is lost or a new one does not land. The JDK checks this file on every PKIX validation, both for each certificate in the path and for the trust anchor, whatever trust store the application uses. Applications that bring their own trust store (AAA is still in Apple's and Microsoft's) are protected too.Proof with the JDK being packaged.
packages/jdk/JdkDistrust.javaruns as a single-file source program. It runs PKIX validation ofEM DV TLS CA - G3Cagainst its real issuers (committed public certificates incve-2026-111943-fixtures.pem), with a fixed validation date and revocation off:Untrusted certificate, so the failure comes from blocked.certs and nothing else.TrustManagerFactorymust offer neither root and still offer at least 80.Any failure fails the build.
Why 48 fingerprints, not 24
The CVE data lists 24: the 16 certificates, plus the ECDSA-malleated twin (
s → n−s) of each of the 8 emSign-issued ones. OpenJDK's ownBlockedCertsConverter(the tool that generatesblocked.certsupstream) also emits each certificate with thesignatureAlgorithmNULL parameter toggled. That field is outside the signed TBS, so anyone can flip it.The build log shows Java accepts that variant. Before the append, all four
EM DV TLS CA - G3Cencodings,-algnullones included, validate on Temurin 21, 25 and 27. OpenSSL 3 rejects the-algnullones, but Java does not. A 24-line list would have left one working re-encoding of every compromised certificate. The 48 are the converter's full set: 8 × 2 for the RSA-signed certificates and 8 × 4 for the ECDSA-signed ones.Malleability is decided by the issuer's signature algorithm.
BlockedCertsConverterdecides it from the subject's public key type. That works by coincidence for the emSign-issued half. For the AAA half (EC subject, RSA signature) it would either fail or emit a bogus fingerprint. Writing fingerprints directly avoids the converter and that bug.The list is generated from the PEMs, and each generated original and malleated fingerprint was checked against the published ones. It lives with
ca-certificatesas the one shared list for every trust store we patch.cve-2026-111943.nclnext to it exports it as aLocal; a Local's path resolves against the.nclthat spells it, so no..is needed.Before / after (verified)
"Before" comes from parsing the cacerts in each pinned tarball, both arches (byte-identical across arches). "After" comes from the build logs. Temurin also carries the other emSign roots (C1, C3, G1). They are untouched: they are not part of this compromise.
Tests
--rebuild --verboseof all three packages in apkgbuildsession (aarch64) passed. Each log shows 6/6 compromised encodingsVALIDbefore, thenUntrusted certificateafter, with the control chainVALIDboth times.cve_2026_111943on each JDK:keytool -list -cacertsstill has ≥ 80 entries and neither root, andblocked.certskeeps its header and lists one malleated fingerprint.min check --packages jdk-21 jdk-25 jdk-27in that session: all 15 checks Pass for each, including standalone tests and fmt. Note that pkgs CI skips standalone tests, so they ran only in the session.mip dumpevaluates on amd64 and arm64. Spec hashes change for the three JDKs and their consumers (jdk,android-sdk,ghidra,gradle,maven,jdtls,tlaplus,dev-language-servers), which pick the fix up throughjdk.Not in this PR
minimal buildcovers it. The amd64 tarballs carry byte-identicalcacertsandblocked.certsto aarch64, and the step is arch-independent.icedtea-7/8,openjdk-9…openjdk-25) installs to/usr/lib/openjdk-Nand nothing onPATH; it is bootstrap only. Its source cacerts carrycomodoaaaca, andemsigneccrootcag3since JDK 23 (openjdk-23/24/25 rungs). Patching it would rebuild the ladder top for no user-facing JDK.build.sh. It will ship OpenJDK's store with both roots, so it needs the samesh ./cve-2026-111943.sh "$JAVA_HOME"step. The script already removes AAA when present.usertrustrsaca, which stays.🤖 Generated with Claude Code