Custom SSL certificates for JDK

I am using custom certificates (via security.pki.certificates in configuration.nix) but they don’t seem to be propagated to JDK. For instance I don’t see the certificates in /nix/store/yirggs7jnyxbhdmk342f6an4ifkgmbgv-openjdk-17.0.1+12/lib/openjdk/lib/security/cacerts and I am getting SSL errors from Java applications such as davmail. Is there a way to install the custom certificates in JDK?

The wiki page Java - NixOS Wiki hasn’t been updated recently but it does mention that OpenJDK has this script nixpkgs/generate-cacerts.pl at master · NixOS/nixpkgs · GitHub to convert the certificates to the JKS format that JDK needs but it is only called in JDK8 and only for the standard certificates in the cacerts package:

The way security.pki works is by creating certificate bundles that are linked somewhere in /etc/, then it’s up to the program to use them.

The problem is I’m not sure you can configure openjdk to use an alternative path. For openjdk 8, the path is inside the package itself and is no good: it can’t be updated without rebuild the package (and everything depending on it).

If you know how to do this, I’ll be happy to try implement a solution in NixOS.

I gave a quick look at how Fedora solves this, but it doesn’t look applicable:

# Install cacerts symlink needed by some apps which hard-code the path
pushd $RPM_BUILD_ROOT%{_jvmdir}/%{sdkdir -- $suffix}/lib/security
  ln -sf /etc/pki/java/cacerts .
popd

We can’t just replace the file with a symlink because it would break on non-NixOS systems.

After some googling I found that JDKs > 8 have this global system property javax.net.ssl.trustStore to specify the location of an alternative trust store. Can it be used somehow to point to the location where security.pki.certificates &co collect the certificates? Where would global java properties go to in NixOS?

1 Like

It seems openjdk is already patched to read the default path from JAVAX_NET_SSL_TRUSTSTORE. The format of this newer keystore is PKCS12: I’m not sure we have tools to convert the bundle to this, I’ll look into this.

1 Like

I had the same issue and the way I solved it is via passing the path via CLI argument

Yes, a quick workaround is to generate the keystore with

nix-shell -p p11-kit --run 'trust extract --format=java-cacerts --purpose=server-auth cacerts'

and pass it from the command line.

1 Like

Nice, I found the existing keystore cacerts from the output of my jdk (e.g. by running sbt 'eval System.getProperty("java.home")', copied it to the new location, added additional certificates, then set JAVAX_NET_SSL_TRUSTSTORE to point to this new cacerts keystore and all worked well.

1 Like

Based on the previous answers, I’ve added the following snippet to my /etc/nixos/configuration.nix:

environment.variables.JAVAX_NET_SSL_TRUSTSTORE =
  let
    caBundle = config.environment.etc."ssl/certs/ca-bundle.crt".source;
    p11kit = pkgs.p11-kit.overrideAttrs (oldAttrs: {
      configureFlags = [
        "--with-trust-paths=${caBundle}"
      ];
    });
  in derivation {
    name = "java-cacerts";
    builder = pkgs.writeShellScript "java-cacerts-builder" ''
      ${p11kit.bin}/bin/trust \
        extract \
        --format=java-cacerts \
        --purpose=server-auth \
        $out
    '';
    system = builtins.currentSystem;
  };
1 Like