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:
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
| Symbol | Type | Description |
|---|---|---|
nativeDistributions.trustedCertificates | ConfigurableFileCollection | CA certificate files (PEM or DER) to import into the bundled JDK's cacerts. |
patchCaCertificates | Gradle task | Copies 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.
trustedCertificatescovers 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 thenative-sslmodule 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
- Code signing — sign and notarize the packaged app.
- native-ssl — trust the operating system's certificate stores at runtime.
- Gradle DSL reference — the full
nucleus { }configuration surface.