Nucleus
Packaging & distribution

Trusted CA certificates

Import private root CA certificates into the JDK bundled with your packaged app so its HTTPS calls trust them.

Nucleus can import private CA certificates into the cacerts keystore of the JDK it bundles with your packaged app. You declare the certificate files in the Gradle DSL, and Nucleus imports them at packaging time so the shipped app trusts them without any change to the user's machine.

This applies when your app runs behind a corporate proxy, a ZTNA gateway, or a filtering service that terminates TLS with a private root CA the default JDK trust store does not recognize. Without the certificate, every HTTPS call fails with SSLHandshakeException.

Declare the certificates

Add the certificate files to nativeDistributions.trustedCertificates:

build.gradle.kts
nucleus {
    application {
        nativeDistributions {
            trustedCertificates.from(
                files(
                    "certs/company-ca.pem",
                    "certs/vpn-root.crt",
                ),
            )
        }
    }
}

Both PEM (-----BEGIN CERTIFICATE-----) and DER (binary) files are accepted. The feature is part of the Nucleus Gradle plugin, so there is no extra dependency to add.

How it works

After createRuntimeImage produces the JLink runtime, Nucleus copies it to runtime-patched/ and runs keytool -import -trustcacerts against the copy's cacerts for each certificate. The original runtime image is never modified in place. The patched copy is then used by both createDistributable and createSandboxedDistributable, so every packaging format embeds the same trusted root.

Each certificate gets a stable alias derived from its file name and content: the file name is lowercased, non-alphanumeric characters become -, it is truncated to 32 characters, and the first 8 hex characters of the content's SHA-256 hash are appended. For example, company-ca.crt becomes company-ca-3a1f8b2c. Because the alias includes the content hash, importing the same certificate twice produces the same alias; keytool reports that the alias already exists and Nucleus skips it, so re-running the build never duplicates entries.

The keytool binary comes from the JDK set through the application's javaHome. When javaHome is unset, Nucleus uses the JVM that runs the build. The keystore is opened with the standard cacerts password changeit.

The patchCaCertificates task is registered only when trustedCertificates is non-empty. It runs automatically as part of packaging; you do not invoke it directly.

API reference

SymbolTypeDescription
nativeDistributions.trustedCertificatesConfigurableFileCollectionCA certificate files (PEM or DER) to import into the bundled JDK's cacerts.
patchCaCertificatesGradle taskCopies the runtime image and imports each certificate. Registered only when trustedCertificates is non-empty.

Notes

  • Only the bundled JDK is patched. The JDK on the user's machine and the JDK running the build are untouched.
  • trustedCertificates covers CAs known at build time, shipped to every user. To trust CAs that end users install themselves at runtime (Keychain on macOS, CryptoAPI on Windows, NSS or system PEM stores on Linux), use the native-ssl module instead.

The two approaches are complementary. Ship build-time CAs with trustedCertificates, and read the user's already-installed CAs with native-ssl.

What's next