Control: found -1 ca-certificates-java/20260311
Control: affects -1 ca-certificates
Hi,
Some additional data on this bug, plus root causes for why the
`update-ca-certificates --fresh` workaround does not reflect deletions.
1. Impact: the eMudhra intermediate compromise (CVE-2026-91403)
================================================================
On Ubuntu 24.04 (ca-certificates 20260816ubuntu0.24.04.1,
ca-certificates-java 20240118), the security update that deselects
"emSign ECC Root CA - G3" and "Comodo AAA Services root" was applied by
unattended-upgrades. /etc/ssl/certs was updated correctly ("4 added,
5 removed"), but /etc/ssl/certs/java/cacerts was left untouched (mtime
unchanged since the package was first installed). Java clients on that
host kept trusting the compromised chains; curl did not:
curl https://dv-g3b-emudhra.we-have-a-problem.com/ -> rejected
java (system JRE, same host, same URL) -> trusted
The same happened on the previous ca-certificates upgrade on that host
(20240203 -> 20260601~24.04.1), so every distrust since installation was
missed.
2. Upgrade path (the original report): still present on sid
===========================================================
This is the same root cause Arnaud analysed in #1069251 (now assigned to
src:ca-certificates). Reproduced in a debian:sid container with
ca-certificates 20260816+nmu1 and ca-certificates-java 20260311 (script
attached): ca-certificates.postinst runs
`update-ca-certificates --hooksdir ""` first, which removes the symlink
without running hooks, and then the deferred trigger run sees
"0 added, 0 removed" and hands an empty list to the jks-keystore hook.
To confirm that the pre-run is the cause (not proposed as the fix),
replacing the hook-less pre-run with a no-op makes the deselected root
disappear from cacerts on the same upgrade path.
A real fix probably needs the hook-less run to preserve its
ADDED/REMOVED lists for the deferred run, or the deferred run to
reconcile cacerts against /etc/ssl/certs instead of relying on a diff.
3. `--fresh` does not reach the hook
====================================
update-ca-certificates never passes --fresh to the hooks:
( cat "$ADDED"
cat "$REMOVED" ) | "$hook" || echo "E: $hook exited with code $?."
so /etc/ca-certificates/update.d/jks-keystore always takes the `*)` branch
and fires `update-ca-certificates-java` rather than
`update-ca-certificates-java-fresh`. With --fresh, update-ca-certificates
first clears all symlinks and recreates them, so the hook receives only
"+" lines and nothing is ever removed from cacerts. That explains why
`update-ca-certificates --fresh` alone is not a workaround.
Passing --fresh through:
( cat "$ADDED"
cat "$REMOVED" ) | "$hook" $( [ "$fresh" = 1 ] && echo --fresh ) || ...
makes the deselected root disappear, but only under an English locale,
because of the next issue.
4. The "fresh" reconciliation is locale-dependent
=================================================
ca-certificates-java.postinst sets only LC_CTYPE=C.UTF-8, and then parses
the existing aliases from translated keytool output:
cacerts_aliases=$(keytool ${castore} -storepass "$storepass" -list -rfc \
| sed -n 's/^Alias name: *debian://ip' | tr '\n' ' ')
keytool follows LC_MESSAGES/LANG for its output ("별칭 이름:" in Korean,
"Aliasname:" in German), so cacerts_aliases is empty and no "-" lines are
generated. Same environment the postinst uses, on sid:
LANG=C.UTF-8 LC_CTYPE=C.UTF-8 -> 120 aliases parsed
LANG=ko_KR.UTF-8 LC_CTYPE=C.UTF-8 -> 0
LANG=de_DE.UTF-8 LC_CTYPE=C.UTF-8 -> 0
Suggested fix:
cacerts_aliases=$(LC_ALL=C.UTF-8 keytool ${castore} ...
(or export LC_ALL=C.UTF-8 at the top of the postinst instead of
LC_CTYPE only).
5. Results (debian:sid, ISRG Root X1 deselected, then checked in cacerts)
=========================================================================
C.UTF-8 ko_KR de_DE
package upgrade path, unpatched present present present
package upgrade path, no pre-run (*) absent absent absent
update-ca-certificates --fresh present present present
--fresh + hook receives --fresh absent present present
--fresh + hook --fresh + LC_ALL fix absent absent absent
(*) diagnostic only, see section 2
Items 2 and 3 are in src:ca-certificates (postinst and
update-ca-certificates), item 4 is in src:ca-certificates-java, hence
the "affects".
Workaround for affected systems, which does not depend on the locale
because the keystore is rebuilt from scratch (as Cyril found):
rm -f /etc/ssl/certs/java/cacerts
update-ca-certificates --fresh
The reproducer script is attached.
Thanks,
Kamilake