Nucleus
Performance & native

Native SSL

Read trusted certificates from the operating system store and merge them with the JVM defaults into a single trust manager.

native-ssl lets you build TLS trust from the operating system's certificate store instead of only the cacerts bundled with your JRE. It reads the trusted roots the OS knows about on macOS, Windows, and Linux, merges them with the JVM defaults, and exposes the result as a single X509TrustManager.

Add the dependency

build.gradle.kts
dependencies {
    implementation("dev.nucleusframework:nucleus.native-ssl:2.0.7")
}

Build a trust manager

NativeTrustManager is an object with three lazily initialized properties. Read whichever one your HTTP stack expects:

import dev.nucleusframework.nativessl.NativeTrustManager
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager

val trustManager: X509TrustManager = NativeTrustManager.trustManager
val sslContext: SSLContext = NativeTrustManager.sslContext
val sslSocketFactory: SSLSocketFactory = NativeTrustManager.sslSocketFactory

If your client is java.net.http, OkHttp, or Ktor, use the Native HTTP adapters instead. They read these properties and wire them into the client for you.

How it works

The first read of any NativeTrustManager property builds a combined X509TrustManager once, lazily and thread-safely, then caches it. The build collects the JVM default accepted issuers, adds the certificates reported by the OS, and loads both sets into a fresh KeyStore that backs the returned trust manager. If the OS reports no certificates, the JVM defaults are used unchanged.

The OS certificates include roots installed by enterprise policy, an MDM, or a TLS-inspection proxy — roots a bundled JRE's cacerts does not contain, which is why HTTPS handshakes to those hosts otherwise fail.

Certificate collection is platform-specific. macOS and Windows use a JNI bridge shipped inside the JAR; Linux reads certificate bundles from disk with no native library.

macOS

The Security framework is called through libnucleus_ssl.dylib (bundled for arm64 and x86_64), in two passes:

  1. System anchorsSecTrustCopyAnchorCertificates() returns every Apple-shipped root.
  2. User and admin domainsSecTrustSettingsCopyCertificates() enumerates certificates with explicit trust settings. Each candidate is evaluated with logic mirroring JetBrains jvm-native-trusted-roots:
    • User trust settings are checked first, then admin.
    • No trust settings means live evaluation through SecTrustEvaluateWithError.
    • An empty trust settings array counts as trusted, per Apple's documentation.
    • kSecTrustSettingsResult must be TrustRoot, and the certificate must be self-signed (DN equality and a signature verified against its own key).
    • kSecTrustSettingsPolicy, when present, must be kSecPolicyAppleSSL.
    • Unknown constraint keys reject the certificate, failing closed rather than relaxing the rules silently.

Windows

Crypt32 is called through nucleus_ssl.dll (bundled for x64 and ARM64). It scans two store types across several store locations:

Store typeInclusion rule
ROOTTrusted root CAs, included unconditionally
CAIntermediate CAs, validated via CertGetCertificateChain and CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE) with cache-only revocation

The locations scanned are CURRENT_USER, LOCAL_MACHINE, CURRENT_USER_GROUP_POLICY, LOCAL_MACHINE_GROUP_POLICY, and LOCAL_MACHINE_ENTERPRISE. Certificates distributed by Group Policy and Active Directory land in stores that SunMSCAPI does not reach.

Inside the native bridge, deduplication is by SHA-1 thumbprint (CERT_HASH_PROP_ID). If the JNI library fails to load, the module falls back to SunMSCAPI's Windows-ROOT, Windows-CA, and Windows-MY keystores.

Linux

Pure JVM, with no shared library. It reads the same paths Go's crypto/x509 does:

PathDistribution
/etc/ssl/certs/ca-certificates.crtDebian, Ubuntu, Gentoo
/etc/pki/tls/certs/ca-bundle.crtFedora, RHEL 6
/etc/ssl/ca-bundle.pemopenSUSE
/etc/pki/tls/cacert.pemOpenELEC
/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pemCentOS, RHEL 7
/etc/ssl/cert.pemAlpine
/etc/ssl/certs/ (dir)SLES 10, SLES 11
/etc/pki/tls/certs/ (dir)Fedora, RHEL
/system/etc/security/cacerts/ (dir)Android

On Linux, certificates are deduplicated by DER content across all sources.

API reference

NativeTrustManager is the only public entry point. It exposes three read-only properties and no methods.

PropertyDescription
NativeTrustManager.trustManager: X509TrustManagerCombined trust manager (JVM defaults plus OS-native roots)
NativeTrustManager.sslContext: SSLContextTLS context initialized with the trust manager
NativeTrustManager.sslSocketFactory: SSLSocketFactorySocket factory derived from sslContext

Certificate collection is internal and dispatches on the current platform. There is no public plug-in point for supplying a custom certificate source.

Notes

ProGuard

The JNI bridge classes must be kept on macOS and Windows. The Nucleus Gradle plugin adds these rules automatically; add them yourself if you maintain ProGuard config manually:

-keep class dev.nucleusframework.nativessl.mac.NativeSslBridge {
    native <methods>;
}
-keep class dev.nucleusframework.nativessl.windows.WindowsSslBridge {
    native <methods>;
}

Logging

Debug logs are tagged NativeCertificateProvider, NativeSslBridge, WindowsCertificateProvider, and LinuxCertificateProvider. They are off by default. Turn them on with:

import dev.nucleusframework.core.runtime.tools.allowNucleusRuntimeLogging

allowNucleusRuntimeLogging = true

What's next

  • Native HTTP — wire the native trust manager into java.net.http, OkHttp, and Ktor.
  • Modules — the full list of Nucleus modules and what each one provides.