Check and remove bad root certificates from Java JDKs on macOS
In response to eMudhra-related certificate issues, these instructions explain how to check Java JDKs on macOS for potentially bad root certificates and remove any that are confirmed to be bad.
Check all Java Development Kits (JDKs) installed on your Mac for potentially bad root certificates. If a bad certificate is found, back up the affected JDK's certificate store, remove the certificate, and run the check again.
Do not delete certificates unless the checker identifies them as bad. Follow the steps in order, and keep a backup before modifying a certificate store.
Step 1: Find your installed JDKs
Open Terminal. Then, run:
/usr/libexec/java_home -V
This lists the Java versions macOS knows about.
Next, run:
ls -1 /Library/Java/JavaVirtualMachines/
This lists JDK installations in the standard macOS Java installation directory.
You might see directories such as:
temurin-8.jdktemurin-21.jdktemurin-25.jdk
Your installed versions might be different.
Step 2: Download the certificate checker
Use a Java program called CheckCerts.java to identify potentially bad root certificates.
Download the program from the following OpenJDK URL.
Run:
curl -fL https://cr.openjdk.org/~mr/CheckCerts.java \
-o /tmp/CheckCerts.java
This saves the source file in your Mac's temporary directory.
Next, create a directory for the compiled program:
mkdir -p /tmp/checkcerts
Compile the program:
javac --release 8 \
-d /tmp/checkcerts \
/tmp/CheckCerts.java
If this command succeeds, continue to Step 3.
If you see an error such as invalid flag: --release, your default Java compiler might be Java 8. Try this command instead:
javac -d /tmp/checkcerts /tmp/CheckCerts.java
If either command fails with another error, stop and ask for help rather than proceeding with an uncompiled checker.
Step 3: Check all installed JDKs
Copy and run the entire command below:
for h in /Library/Java/JavaVirtualMachines/*.jdk/Contents/Home; do
if [ -x "$h/bin/java" ]; then
echo ""
echo "===== Checking: $h ====="
"$h/bin/java" -cp /tmp/checkcerts CheckCerts
fi
done
This command runs the checker separately with each JDK found in the standard installation directory.
Wait for the command to finish. Review the output for every JDK.
Understand the results
Case A: No bad root certificates found
Example:
===== Checking: /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home =====
Java runtime version 21.0.13+9-LTS at /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
No bad root certificates found
This JDK has passed the check. Continue reviewing the results for the other JDKs.
Case B: A bad root certificate is found
Example:
===== Checking: /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home =====
Java runtime version 21.0.13+9-LTS at /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
BAD ROOT: CN=emSign Root CA - G1,O=eMudhra Technologies Limited,OU=emSign PKI,C=IN
This means the checker has identified a certificate that needs to be investigated and removed according to the instructions.
Note the JDK path and the complete certificate name. Proceed to Step 4.
Case C: An error occurs
If the checker reports a Java error or does not produce either of the expected results, do not assume the JDK has passed. Record the error and ask for help.
Step 4: Back up the affected JDK's certificate store
Only perform this step for a JDK that has a bad root certificate.
The certificate store, called cacerts, contains certificates that Java trusts.
For example, if the affected JDK is Temurin 21, run:
h=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
sudo cp "$h/lib/security/cacerts" \
"$h/lib/security/cacerts.bak-emudhra"
Enter your Mac password if prompted.
This creates a backup named cacerts.bak-emudhra next to the original certificate store.
If a backup with that name already exists, do not overwrite it blindly. Choose a different backup filename first.
Certificate store locations
The standard locations differ by Java version:
- Temurin 21 and 25:
lib/security/cacerts - Temurin 8:
jre/lib/security/cacerts
If you are using a different JDK distribution or installation layout, confirm the correct location before proceeding.
Step 5: Find the bad certificate's alias
An alias is the identifier Java uses to refer to a certificate in its certificate store.
The alias might not look exactly like the certificate's full name.
For Temurin 21, run:
"$h/bin/keytool" -list -cacerts -storepass changeit \
| grep -i 'cn_emsign_root_ca__g1'
This searches for the alias associated with the emSign Root CA - G1 certificate.
Compare the result with the bad certificate reported in Step 3.
If the command returns a matching alias, copy its complete name.
If it returns no result, or you cannot confidently match the alias to the bad certificate, stop and ask for help. Do not guess an alias.
Step 6: Delete the bad certificate
Only proceed when you have identified the exact alias and confirmed it corresponds to the certificate flagged by the checker.
Replace PASTE_THE_EXACT_ALIAS_HERE with the complete alias from Step 5.
sudo "$h/bin/keytool" -delete -cacerts \
-storepass changeit \
-alias 'PASTE_THE_EXACT_ALIAS_HERE'
Enter your Mac password if prompted.
If there is no output after running the command, then the certificate was likely successfully deleted.
This example is for the emSign Root CA - G1 certificate in Temurin 21. Other certificates and JDK versions might use different aliases and certificate-store paths. Do not reuse this command unchanged for a different certificate.
Step 7: Run the certificate check again
After deleting the bad certificate, rerun the checker with the affected JDK.
For Temurin 21, run:
"$h/bin/java" -cp /tmp/checkcerts CheckCerts
If the output is:
No bad root certificates found
the affected JDK has passed the check.
If another bad root certificate appears, repeat the investigation and removal process for that certificate. Back up the current certificate store before making any additional changes.
If the same certificate still appears, stop and verify that you deleted the correct alias from the correct JDK's certificate store.
Step 8: Check all JDKs again
After addressing any bad certificates, rerun the full check from Step 3:
for h in /Library/Java/JavaVirtualMachines/*.jdk/Contents/Home; do
if [ -x "$h/bin/java" ]; then
echo ""
echo "===== Checking: $h ====="
"$h/bin/java" -cp /tmp/checkcerts CheckCerts
fi
done
Review the output for every JDK.
Your checks are complete when every JDK checked reports:
No bad root certificates found
If a JDK produces an error or reports another bad certificate, resolve that issue before reporting that all checks have passed.
Troubleshooting
The following troubleshooting tips address common issues encountered during the certificate check and removal process.
command not found: javac
Your Terminal might not be using a JDK that includes the Java compiler. Check your installed JDKs in Step 1 and ask for help configuring the compiler.
Permission denied
Some operations require administrator privileges. For the backup and certificate deletion commands, use the provided sudo commands. Do not change file permissions unnecessarily.
Keystore was tampered with, or password was incorrect
The command assumes the standard Java certificate-store password is changeit. If this error appears, stop and ask whether your installation uses a different password.
Alias does not exist
The alias might be different from the expected name, or you might be targeting the wrong JDK. Repeat Step 5 and confirm the full alias before trying again.
BAD ROOT still appears after deletion
Confirm that you deleted the certificate from the same JDK path that reported it. Check the alias and certificate-store path again. Do not repeatedly delete certificates without verifying the target.