javamacosscalasslkeystore

How to add self-signed generated certificate to trusted certificates from inside a Java keystore?


I have a class EncryptionManager that generates public and private keys along with a x509 certificate. These are stored inside a Java keystore.

How would I go about programatically importing this certificate into the computers keychain?

I know the commands to run in a terminal, I just wondered if there is a way to do it from Java without needing to spawn a process that runs bash?

EDIT:

Someone pointed out this might be a duplicate. Let me expand a little.

My KeyStore is also storing other keys and certificates for secure communication with other clients, not just SSL. The other answer tells me how to point the system at my keystore, but not how I would specify which key/cert to use.

Also, does the other answer work for all systems? On a Mac, the cert must be added to the System.keychain using sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ~/.localhost-ssl/localhost.crt, which I would like to do without spawning a bash process if possible.


Solution

  • I tried couple of different keychains but somehow it is restricted for the following keychain files:

    The only one which I was able to append additional certificates was to the following keychain file:

    The following code should do the trick and additional it will print the console output if you have any errors:

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.nio.charset.StandardCharsets;
    import java.util.stream.Collectors;
    
    public class App {
    
        public static void main(String[] args) throws IOException {
            ProcessBuilder processBuilder = new ProcessBuilder(
                    "security", "add-trusted-cert", 
                    "-d", "-r", "trustAsRoot", 
                    "-k", "/Users/[MY_USER]/Library/Keychains/login.keychain-db", 
                    "/absolute-path/to/my-custom-root-ca.crt");
    
            Process process = processBuilder.start();
    
            String consoleOutput = getConsoleOutput(process);
            System.out.println(consoleOutput);
        }
    
        private static String getConsoleOutput(Process process) throws IOException {
            try (InputStream inputStream = process.getInputStream();
                 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
                 BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
    
                return bufferedReader.lines()
                        .collect(Collectors.joining(System.lineSeparator()));
            }
        }
    
    }
    

    You don't need to include the sudo command, but you will be prompted to scan either your finger or enter the password. I am not sure how to avoid that part yet, but my assumption is that it is required.

    Another sidenote to this solution is that a path to a binary certificate is required. So if you use a keystore file either in memory or on the filesystem you first need to extract the certificates from it and save it on the filesystem. Get the absolute file paths for all of those files and loop through it for every file with the mac command in the code example.