or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

admin-jmx.mdansi-support.mdaot-native-image.mdapplication-info.mdavailability.mdbootstrap.mdbootstrapping.mdbuilder.mdcloud-platform.mdconfiguration-annotations.mdconfiguration-data.mdconfiguration-properties.mdconversion.mddiagnostics.mdenvironment-property-sources.mdindex.mdjson-support.mdlifecycle-events.mdlogging.mdorigin-tracking.mdresource-loading.mdretry-support.mdssl-tls.mdstartup-metrics.mdsupport.mdsystem-utilities.mdtask-execution.mdthreading.mdutilities.mdvalidation.mdweb-support.md
tile.json

ssl-tls.mddocs/

Spring Boot SSL/TLS Bundle Management

Quick Reference

This documentation has been enhanced for AI coding agents with comprehensive examples, complete API signatures, thread safety notes, error handling patterns, and production-ready usage patterns.

Core SSL Bundle Components

ComponentPurposeThread SafetyKey Use Cases
SslBundleComplete SSL configuration bundleThread-safe (immutable)Creating SSLContext for servers/clients
SslStoreBundleKey and trust store accessThread-safeManaging certificates and keys
SslManagerBundleKeyManager and TrustManager factoryThread-safeCreating SSL managers
SslBundleKeyKey alias and password referenceThread-safe (immutable)Identifying specific keys in keystore
SslOptionsCipher suites and protocol configThread-safe (immutable)Fine-tuning SSL settings
SslBundleRegistryCentral bundle managementThread-safeManaging multiple SSL configurations

Store Bundle Implementations

ClassFormatThread SafetyKey Features
PemSslStoreBundlePEM-encodedThread-safeCertificate chains, encrypted keys, file/classpath loading
JksSslStoreBundleJKS/PKCS12Thread-safeBinary keystores, hardware PKCS11 support
PemSslStorePEM contentThread-safe (immutable)In-memory PEM storage with alias/password
JksSslStoreDetailsJKS configurationThread-safe (record)Keystore location, type, provider, password

PEM Content Handling

ClassPurposeThread SafetyKey Operations
PemContentParsed PEM contentThread-safeLoad certificates, parse private keys
PemCertificateParserParse X.509 certificatesThread-safeExtract certificate chains from PEM
PemPrivateKeyParserParse encrypted keysThread-safeDecrypt PKCS#1, PKCS#8 private keys
PemSslStoreDetailsPEM store configurationThread-safe (record)Certificate/key file paths

Bundle Registry Operations

MethodPurposeThread SafetyThrows
registerBundle(name, bundle)Add new bundleThread-safeIllegalStateException if exists
updateBundle(name, bundle)Update existing bundleThread-safeNoSuchSslBundleException if missing
getBundle(name)Retrieve bundleThread-safeNoSuchSslBundleException if missing
addBundleUpdateHandler(name, handler)Add update callbackThread-safeNone

Package: org.springframework.boot.ssl Version: 4.0.0 Since: 3.1.0

Spring Boot provides a comprehensive SSL/TLS bundle management system that simplifies the configuration and management of SSL certificates, private keys, and trust stores. This system supports both PEM-encoded certificates and Java KeyStore (JKS) formats, providing a unified API for SSL configuration across different technologies.

Core Interfaces

SslBundle

The main interface representing a bundle of SSL configuration materials.

package org.springframework.boot.ssl;

/**
 * A bundle of trust material that can be used to establish an SSL connection.
 *
 * @author Scott Frederick
 * @author Moritz Halbritter
 * @since 3.1.0
 */
public interface SslBundle {

    /**
     * The default protocol to use.
     */
    String DEFAULT_PROTOCOL = "TLS";

    /**
     * Return the SslStoreBundle that can be used to access this bundle's key and
     * trust stores.
     *
     * @return the SslStoreBundle instance for this bundle
     */
    SslStoreBundle getStores();

    /**
     * Return a reference to the key that should be used for this bundle or
     * SslBundleKey.NONE.
     *
     * @return a reference to the SSL key that should be used
     */
    SslBundleKey getKey();

    /**
     * Return SslOptions that should be applied when establishing the SSL
     * connection.
     *
     * @return the options that should be applied
     */
    SslOptions getOptions();

    /**
     * Return the protocol to use when establishing the connection. Values should be
     * supported by SSLContext.getInstance(String).
     *
     * @return the SSL protocol
     * @see javax.net.ssl.SSLContext#getInstance(String)
     */
    String getProtocol();

    /**
     * Return the SslManagerBundle that can be used to access this bundle's
     * KeyManager and TrustManager instances.
     *
     * @return the SslManagerBundle instance for this bundle
     */
    SslManagerBundle getManagers();

    /**
     * Factory method to create a new SSLContext for this bundle.
     *
     * @return a new SSLContext instance
     */
    default SSLContext createSslContext() {
        return getManagers().createSslContext(getProtocol());
    }

    /**
     * Factory method to create a new SslBundle instance.
     *
     * @param stores the stores or null
     * @return a new SslBundle instance
     */
    static SslBundle of(@Nullable SslStoreBundle stores) {
        return of(stores, null, null);
    }

    /**
     * Factory method to create a new SslBundle instance.
     *
     * @param stores the stores or null
     * @param key the key or null
     * @return a new SslBundle instance
     */
    static SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key) {
        return of(stores, key, null);
    }

    /**
     * Factory method to create a new SslBundle instance.
     *
     * @param stores the stores or null
     * @param key the key or null
     * @param options the options or null
     * @return a new SslBundle instance
     */
    static SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key, @Nullable SslOptions options) {
        return of(stores, key, options, null);
    }

    /**
     * Factory method to create a new SslBundle instance.
     *
     * @param stores the stores or null
     * @param key the key or null
     * @param options the options or null
     * @param protocol the protocol or null
     * @return a new SslBundle instance
     */
    static SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key,
                        @Nullable SslOptions options, @Nullable String protocol) {
        return of(stores, key, options, protocol, null);
    }

    /**
     * Factory method to create a new SslBundle instance.
     *
     * @param stores the stores or null
     * @param key the key or null
     * @param options the options or null
     * @param protocol the protocol or null
     * @param managers the managers or null
     * @return a new SslBundle instance
     */
    static SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key,
                        @Nullable SslOptions options, @Nullable String protocol,
                        @Nullable SslManagerBundle managers) {
        // Implementation provided by Spring Boot
    }

    /**
     * Factory method to create a new SslBundle which uses the system defaults.
     *
     * @return a new SslBundle instance
     * @since 3.5.0
     */
    static SslBundle systemDefault() {
        // Uses system KeyManagerFactory and TrustManagerFactory
    }
}

SslBundles

Interface for accessing a managed set of SSL bundles by name.

package org.springframework.boot.ssl;

/**
 * A managed set of SslBundle instances that can be retrieved by name.
 *
 * @author Scott Frederick
 * @author Moritz Halbritter
 * @author Jonatan Ivanov
 * @since 3.1.0
 */
public interface SslBundles {

    /**
     * Return an SslBundle with the provided name.
     *
     * @param name the bundle name
     * @return the bundle
     * @throws NoSuchSslBundleException if a bundle with the provided name does not exist
     */
    SslBundle getBundle(String name) throws NoSuchSslBundleException;

    /**
     * Add a handler that will be called each time the named bundle is updated.
     *
     * @param name the bundle name
     * @param updateHandler the handler that should be called
     * @throws NoSuchSslBundleException if a bundle with the provided name does not exist
     * @since 3.2.0
     */
    void addBundleUpdateHandler(String name, Consumer<SslBundle> updateHandler)
            throws NoSuchSslBundleException;

    /**
     * Add a handler that will be called each time a bundle is registered. The handler
     * will be called with the bundle name and the bundle.
     *
     * @param registerHandler the handler that should be called
     * @since 3.5.0
     */
    void addBundleRegisterHandler(BiConsumer<String, SslBundle> registerHandler);

    /**
     * Return the names of all bundles managed by this instance.
     *
     * @return the bundle names
     * @since 3.4.0
     */
    List<String> getBundleNames();
}

SslBundleRegistry

Interface for registering and updating SSL bundles.

package org.springframework.boot.ssl;

/**
 * Interface that can be used to register an SslBundle for a given name.
 *
 * @author Scott Frederick
 * @author Moritz Halbritter
 * @since 3.1.0
 */
public interface SslBundleRegistry {

    /**
     * Register a named SslBundle.
     *
     * @param name the bundle name
     * @param bundle the bundle
     */
    void registerBundle(String name, SslBundle bundle);

    /**
     * Updates an SslBundle.
     *
     * @param name the bundle name
     * @param updatedBundle the updated bundle
     * @throws NoSuchSslBundleException if the bundle cannot be found
     * @since 3.2.0
     */
    void updateBundle(String name, SslBundle updatedBundle)
            throws NoSuchSslBundleException;
}

DefaultSslBundleRegistry

Default implementation combining registry and bundle access.

package org.springframework.boot.ssl;

/**
 * Default SslBundleRegistry implementation.
 *
 * @author Scott Frederick
 * @author Moritz Halbritter
 * @author Phillip Webb
 * @author Jonatan Ivanov
 * @since 3.1.0
 */
public class DefaultSslBundleRegistry implements SslBundleRegistry, SslBundles {

    /**
     * Create a new empty DefaultSslBundleRegistry.
     */
    public DefaultSslBundleRegistry() {
    }

    /**
     * Create a new DefaultSslBundleRegistry with a single bundle.
     *
     * @param name the bundle name
     * @param bundle the bundle
     */
    public DefaultSslBundleRegistry(String name, SslBundle bundle) {
    }

    @Override
    public void registerBundle(String name, SslBundle bundle) {
        // Registers bundle, throws if bundle with same name already exists
    }

    @Override
    public void updateBundle(String name, SslBundle updatedBundle) {
        // Updates bundle, triggers registered update handlers
    }

    @Override
    public SslBundle getBundle(String name) {
        // Returns bundle or throws NoSuchSslBundleException
    }

    @Override
    public void addBundleUpdateHandler(String name, Consumer<SslBundle> updateHandler)
            throws NoSuchSslBundleException {
        // Adds handler that will be called when bundle is updated
    }

    @Override
    public void addBundleRegisterHandler(BiConsumer<String, SslBundle> registerHandler) {
        // Adds handler that will be called when any bundle is registered
    }

    @Override
    public List<String> getBundleNames() {
        // Returns sorted, unmodifiable list of all bundle names
    }
}

SSL Store Components

SslStoreBundle

Interface representing key and trust stores.

package org.springframework.boot.ssl;

/**
 * A bundle of key and trust stores that can be used to establish an SSL connection.
 *
 * @author Scott Frederick
 * @since 3.1.0
 */
public interface SslStoreBundle {

    /**
     * SslStoreBundle that returns null for each method.
     */
    SslStoreBundle NONE = of(null, null, null);

    /**
     * Return a key store generated from the trust material or null.
     *
     * @return the key store
     */
    @Nullable KeyStore getKeyStore();

    /**
     * Return the password for the key in the key store or null.
     *
     * @return the key password
     */
    @Nullable String getKeyStorePassword();

    /**
     * Return a trust store generated from the trust material or null.
     *
     * @return the trust store
     */
    @Nullable KeyStore getTrustStore();

    /**
     * Factory method to create a new SslStoreBundle instance.
     *
     * @param keyStore the key store or null
     * @param keyStorePassword the key store password or null
     * @param trustStore the trust store or null
     * @return a new SslStoreBundle instance
     */
    static SslStoreBundle of(KeyStore keyStore, String keyStorePassword,
                             KeyStore trustStore) {
        return new SslStoreBundle() {
            @Override
            public KeyStore getKeyStore() {
                return keyStore;
            }

            @Override
            public KeyStore getTrustStore() {
                return trustStore;
            }

            @Override
            public String getKeyStorePassword() {
                return keyStorePassword;
            }
        };
    }
}

SslManagerBundle

Interface for accessing KeyManager and TrustManager instances.

package org.springframework.boot.ssl;

/**
 * A bundle of key and trust managers that can be used to establish an SSL connection.
 * Instances are usually created from an SslStoreBundle.
 *
 * @author Scott Frederick
 * @author Moritz Halbritter
 * @since 3.1.0
 */
public interface SslManagerBundle {

    /**
     * Return the KeyManager instances used to establish identity.
     *
     * @return the key managers
     */
    default KeyManager[] getKeyManagers() {
        return getKeyManagerFactory().getKeyManagers();
    }

    /**
     * Return the KeyManagerFactory used to establish identity.
     *
     * @return the key manager factory
     */
    KeyManagerFactory getKeyManagerFactory();

    /**
     * Return the TrustManager instances used to establish trust.
     *
     * @return the trust managers
     */
    default TrustManager[] getTrustManagers() {
        return getTrustManagerFactory().getTrustManagers();
    }

    /**
     * Return the TrustManagerFactory used to establish trust.
     *
     * @return the trust manager factory
     */
    TrustManagerFactory getTrustManagerFactory();

    /**
     * Factory method to create a new SSLContext for the key managers and
     * trust managers managed by this instance.
     *
     * @param protocol the standard name of the SSL protocol
     * @return a new SSLContext instance
     * @see javax.net.ssl.SSLContext#getInstance(String)
     */
    default SSLContext createSslContext(String protocol) {
        try {
            SSLContext sslContext = SSLContext.getInstance(protocol);
            sslContext.init(getKeyManagers(), getTrustManagers(), null);
            return sslContext;
        }
        catch (Exception ex) {
            throw new IllegalStateException(
                "Could not load SSL context: " + ex.getMessage(), ex);
        }
    }

    /**
     * Factory method to create a new SslManagerBundle instance.
     *
     * @param keyManagerFactory the key manager factory
     * @param trustManagerFactory the trust manager factory
     * @return a new SslManagerBundle instance
     */
    static SslManagerBundle of(KeyManagerFactory keyManagerFactory,
                                TrustManagerFactory trustManagerFactory) {
        return new SslManagerBundle() {
            @Override
            public KeyManagerFactory getKeyManagerFactory() {
                return keyManagerFactory;
            }

            @Override
            public TrustManagerFactory getTrustManagerFactory() {
                return trustManagerFactory;
            }
        };
    }

    /**
     * Factory method to create a new SslManagerBundle backed by the given
     * SslStoreBundle and SslBundleKey.
     *
     * @param storeBundle the SSL store bundle
     * @param key the key reference
     * @return a new SslManagerBundle instance
     */
    static SslManagerBundle from(SslStoreBundle storeBundle, SslBundleKey key) {
        // Returns DefaultSslManagerBundle instance
        // Creates KeyManagerFactory and TrustManagerFactory from stores
    }

    /**
     * Factory method to create a new SslManagerBundle using the given
     * TrustManagerFactory and the default KeyManagerFactory.
     *
     * @param trustManagerFactory the trust manager factory
     * @return a new SslManagerBundle instance
     * @since 3.5.0
     */
    static SslManagerBundle from(TrustManagerFactory trustManagerFactory) {
        // Creates default KeyManagerFactory initialized with (null, null)
        // Returns SslManagerBundle.of(defaultKeyManagerFactory, trustManagerFactory)
    }

    /**
     * Factory method to create a new SslManagerBundle using the given
     * TrustManagers and the default KeyManagerFactory.
     *
     * @param trustManagers the trust managers to use
     * @return a new SslManagerBundle instance
     * @since 3.5.0
     */
    static SslManagerBundle from(TrustManager... trustManagers) {
        // Creates default KeyManagerFactory and TrustManagerFactory
        // Wraps TrustManagerFactory with FixedTrustManagerFactory using provided managers
        // Returns SslManagerBundle.of(defaultKeyManagerFactory, fixedTrustManagerFactory)
    }
}

SslOptions

Configuration options for SSL connections.

package org.springframework.boot.ssl;

/**
 * Configuration options that should be applied when establishing an SSL connection.
 *
 * @author Scott Frederick
 * @since 3.1.0
 */
public interface SslOptions {

    /**
     * SslOptions that returns null results.
     */
    SslOptions NONE = of(null, (Set<String>) null);

    /**
     * Return if any SSL options have been specified.
     *
     * @return true if SSL options have been specified
     */
    default boolean isSpecified() {
        return (getCiphers() != null) || (getEnabledProtocols() != null);
    }

    /**
     * Return the ciphers that can be used or null. The cipher names in this set
     * should be compatible with those supported by SSLEngine.getSupportedCipherSuites().
     *
     * @return the ciphers that can be used or null
     */
    String @Nullable [] getCiphers();

    /**
     * Return the protocols that should be enabled or null. The protocols names in
     * this set should be compatible with those supported by SSLEngine.getSupportedProtocols().
     *
     * @return the protocols to enable or null
     */
    String @Nullable [] getEnabledProtocols();

    /**
     * Factory method to create a new SslOptions instance.
     *
     * @param ciphers the ciphers
     * @param enabledProtocols the enabled protocols
     * @return a new SslOptions instance
     */
    static SslOptions of(String[] ciphers, String[] enabledProtocols) {
        return new SslOptions() {
            @Override
            public String[] getCiphers() {
                return ciphers;
            }

            @Override
            public String[] getEnabledProtocols() {
                return enabledProtocols;
            }
        };
    }

    /**
     * Factory method to create a new SslOptions instance.
     *
     * @param ciphers the ciphers
     * @param enabledProtocols the enabled protocols
     * @return a new SslOptions instance
     */
    static SslOptions of(Set<String> ciphers, Set<String> enabledProtocols) {
        // Converts Sets to arrays and delegates to of(String[], String[])
        return of(toArray(ciphers), toArray(enabledProtocols));
    }

    /**
     * Helper method that provides a null-safe way to convert a String[] to a
     * Collection for client libraries to use.
     *
     * @param array the array to convert
     * @return a collection or null
     */
    static Set<String> asSet(String[] array) {
        return (array != null) ?
            Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(array))) : null;
    }
}

SslBundleKey

Reference to a specific key within a key store.

package org.springframework.boot.ssl;

/**
 * A reference to a single key obtained via SslBundle.
 *
 * @author Phillip Webb
 * @since 3.1.0
 */
public interface SslBundleKey {

    /**
     * SslBundleKey that returns no values.
     */
    SslBundleKey NONE = of(null, null);

    /**
     * Return the password that should be used to access the key or null if no
     * password is required.
     *
     * @return the key password
     */
    @Nullable String getPassword();

    /**
     * Return the alias of the key or null if the key has no alias.
     *
     * @return the key alias
     */
    @Nullable String getAlias();

    /**
     * Assert that the alias is contained in the given keystore.
     *
     * @param keyStore the keystore to check
     */
    default void assertContainsAlias(@Nullable KeyStore keyStore) {
        String alias = getAlias();
        if (StringUtils.hasLength(alias) && keyStore != null) {
            try {
                Assert.state(keyStore.containsAlias(alias),
                    () -> String.format("Keystore does not contain alias '%s'", alias));
            }
            catch (KeyStoreException ex) {
                throw new IllegalStateException(
                    String.format("Could not determine if keystore contains alias '%s'",
                                 alias), ex);
            }
        }
    }

    /**
     * Factory method to create a new SslBundleKey instance.
     *
     * @param password the password used to access the key
     * @return a new SslBundleKey instance
     */
    static SslBundleKey of(String password) {
        return of(password, null);
    }

    /**
     * Factory method to create a new SslBundleKey instance.
     *
     * @param password the password used to access the key
     * @param alias the alias of the key
     * @return a new SslBundleKey instance
     */
    static SslBundleKey of(String password, String alias) {
        return new SslBundleKey() {
            @Override
            public String getPassword() {
                return password;
            }

            @Override
            public String getAlias() {
                return alias;
            }
        };
    }
}

PEM Support

The org.springframework.boot.ssl.pem package provides comprehensive support for PEM-encoded certificates and private keys.

PemSslStoreBundle

SslStoreBundle implementation for PEM-encoded content.

package org.springframework.boot.ssl.pem;

/**
 * SslStoreBundle backed by PEM-encoded certificates and private keys.
 *
 * @author Scott Frederick
 * @author Phillip Webb
 * @author Moritz Halbritter
 * @since 3.1.0
 */
public class PemSslStoreBundle implements SslStoreBundle {

    /**
     * Create a new PemSslStoreBundle instance.
     *
     * @param keyStoreDetails the key store details
     * @param trustStoreDetails the trust store details
     */
    public PemSslStoreBundle(PemSslStoreDetails keyStoreDetails,
                             PemSslStoreDetails trustStoreDetails) {
    }

    /**
     * Create a new PemSslStoreBundle instance.
     *
     * @param pemKeyStore the PEM key store
     * @param pemTrustStore the PEM trust store
     * @since 3.2.0
     */
    public PemSslStoreBundle(PemSslStore pemKeyStore, PemSslStore pemTrustStore) {
    }

    @Override
    public KeyStore getKeyStore() {
        // Returns KeyStore created from PEM content
    }

    @Override
    public String getKeyStorePassword() {
        // Always returns null for PEM stores
    }

    @Override
    public KeyStore getTrustStore() {
        // Returns KeyStore created from PEM content
    }
}

PemSslStore

Interface representing an individual PEM-based store.

package org.springframework.boot.ssl.pem;

/**
 * An individual trust or key store that has been loaded from PEM content.
 *
 * @author Phillip Webb
 * @since 3.2.0
 */
public interface PemSslStore {

    /**
     * The key store type, for example JKS or PKCS11. A null value
     * will use KeyStore.getDefaultType().
     *
     * @return the key store type
     */
    @Nullable String type();

    /**
     * The alias used when setting entries in the KeyStore.
     *
     * @return the alias
     */
    @Nullable String alias();

    /**
     * The password used when setting key entries in the KeyStore.
     *
     * @return the password
     */
    @Nullable String password();

    /**
     * The certificates for this store. When a private key is present the returned
     * value is treated as a certificate chain, otherwise it is treated as a list of
     * certificates that should all be registered.
     *
     * @return the X509 certificates
     */
    @Nullable List<X509Certificate> certificates();

    /**
     * The private key for this store or null.
     *
     * @return the private key
     */
    @Nullable PrivateKey privateKey();

    /**
     * Return a new PemSslStore instance with a new alias.
     *
     * @param alias the new alias
     * @return a new PemSslStore instance
     */
    default PemSslStore withAlias(@Nullable String alias) {
        return of(type(), alias, password(), certificates(), privateKey());
    }

    /**
     * Return a new PemSslStore instance with a new password.
     *
     * @param password the new password
     * @return a new PemSslStore instance
     */
    default PemSslStore withPassword(@Nullable String password) {
        return of(type(), alias(), password, certificates(), privateKey());
    }

    /**
     * Return a PemSslStore instance loaded using the given PemSslStoreDetails.
     *
     * @param details the PEM store details
     * @return a loaded PemSslStore or null
     */
    static @Nullable PemSslStore load(@Nullable PemSslStoreDetails details) {
        // Loads PEM content from details using ApplicationResourceLoader
        // Returns LoadedPemSslStore wrapping the details
        return load(details, ApplicationResourceLoader.get());
    }

    /**
     * Return a PemSslStore instance loaded using the given PemSslStoreDetails.
     *
     * @param details the PEM store details
     * @param resourceLoader the resource loader used to load content
     * @return a loaded PemSslStore or null
     * @since 3.3.5
     */
    static @Nullable PemSslStore load(@Nullable PemSslStoreDetails details, ResourceLoader resourceLoader) {
        // Returns null if details is null or empty
        // Otherwise returns new LoadedPemSslStore(details, resourceLoader)
        return (details == null || details.isEmpty()) ? null
            : new LoadedPemSslStore(details, resourceLoader);
    }

    /**
     * Factory method that can be used to create a new PemSslStore with the given values.
     *
     * @param type the key store type
     * @param certificates the certificates for this store
     * @param privateKey the private key
     * @return a new PemSslStore instance
     */
    static PemSslStore of(@Nullable String type, List<X509Certificate> certificates,
                          @Nullable PrivateKey privateKey) {
        return of(type, null, null, certificates, privateKey);
    }

    /**
     * Factory method that can be used to create a new PemSslStore with the given values.
     *
     * @param certificates the certificates for this store
     * @param privateKey the private key
     * @return a new PemSslStore instance
     */
    static PemSslStore of(List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {
        return of(null, null, null, certificates, privateKey);
    }

    /**
     * Factory method that can be used to create a new PemSslStore with the given values.
     *
     * @param type the key store type
     * @param alias the alias used when setting entries in the KeyStore
     * @param password the password used setting key entries in the KeyStore
     * @param certificates the certificates for this store
     * @param privateKey the private key
     * @return a new PemSslStore instance
     */
    static PemSslStore of(String type, String alias, String password,
                          List<X509Certificate> certificates, PrivateKey privateKey) {
        return new PemSslStore() {
            @Override
            public String type() {
                return type;
            }

            @Override
            public String alias() {
                return alias;
            }

            @Override
            public String password() {
                return password;
            }

            @Override
            public List<X509Certificate> certificates() {
                return certificates;
            }

            @Override
            public PrivateKey privateKey() {
                return privateKey;
            }
        };
    }
}

PemSslStoreDetails

Configuration details for PEM-based stores.

package org.springframework.boot.ssl.pem;

/**
 * Details for an individual trust or key store in a PemSslStoreBundle.
 *
 * @param type the key store type, for example JKS or PKCS11. A null value
 *             will use KeyStore.getDefaultType()
 * @param alias the alias used when setting entries in the KeyStore
 * @param password the password used setting key entries in the KeyStore
 * @param certificates the certificates content (either the PEM content itself or a
 *                     reference to the resource to load). When a private key is present
 *                     this value is treated as a certificate chain, otherwise it is
 *                     treated as a list of certificates that should all be registered
 * @param privateKey the private key content (either the PEM content itself or a
 *                   reference to the resource to load)
 * @param privateKeyPassword a password used to decrypt an encrypted private key
 * @author Scott Frederick
 * @author Phillip Webb
 * @since 3.1.0
 */
public record PemSslStoreDetails(@Nullable String type, @Nullable String alias, @Nullable String password,
                                 @Nullable String certificates, @Nullable String privateKey,
                                 @Nullable String privateKeyPassword) {

    /**
     * Create a new PemSslStoreDetails instance.
     *
     * @param type the key store type
     * @param certificate the certificate content
     * @param privateKey the private key content
     * @param privateKeyPassword a password used to decrypt an encrypted private key
     */
    public PemSslStoreDetails(String type, String certificate, String privateKey,
                              String privateKeyPassword) {
        this(type, null, null, certificate, privateKey, privateKeyPassword);
    }

    /**
     * Create a new PemSslStoreDetails instance.
     *
     * @param type the key store type
     * @param certificate the certificate content
     * @param privateKey the private key content
     */
    public PemSslStoreDetails(String type, String certificate, String privateKey) {
        this(type, certificate, privateKey, null);
    }

    /**
     * Return a new PemSslStoreDetails instance with a new alias.
     *
     * @param alias the new alias
     * @return a new PemSslStoreDetails instance
     * @since 3.2.0
     */
    public PemSslStoreDetails withAlias(@Nullable String alias) {
        return new PemSslStoreDetails(this.type, alias, this.password,
                                      this.certificates, this.privateKey,
                                      this.privateKeyPassword);
    }

    /**
     * Return a new PemSslStoreDetails instance with a new password.
     *
     * @param password the new password
     * @return a new PemSslStoreDetails instance
     * @since 3.2.0
     */
    public PemSslStoreDetails withPassword(@Nullable String password) {
        return new PemSslStoreDetails(this.type, this.alias, password,
                                      this.certificates, this.privateKey,
                                      this.privateKeyPassword);
    }

    /**
     * Return a new PemSslStoreDetails instance with a new private key.
     *
     * @param privateKey the new private key
     * @return a new PemSslStoreDetails instance
     */
    public PemSslStoreDetails withPrivateKey(@Nullable String privateKey) {
        return new PemSslStoreDetails(this.type, this.alias, this.password,
                                      this.certificates, privateKey,
                                      this.privateKeyPassword);
    }

    /**
     * Return a new PemSslStoreDetails instance with a new private key password.
     *
     * @param privateKeyPassword the new private key password
     * @return a new PemSslStoreDetails instance
     */
    public PemSslStoreDetails withPrivateKeyPassword(@Nullable String privateKeyPassword) {
        return new PemSslStoreDetails(this.type, this.alias, this.password,
                                      this.certificates, this.privateKey,
                                      privateKeyPassword);
    }

    /**
     * Factory method to create a new PemSslStoreDetails instance for the given
     * certificate. Note: This method doesn't actually check if the provided value
     * only contains a single certificate. It is functionally equivalent to
     * forCertificates(String).
     *
     * @param certificate the certificate content
     * @return a new PemSslStoreDetails instance
     */
    public static PemSslStoreDetails forCertificate(@Nullable String certificate) {
        return forCertificates(certificate);
    }

    /**
     * Factory method to create a new PemSslStoreDetails instance for the given
     * certificates.
     *
     * @param certificates the certificates content
     * @return a new PemSslStoreDetails instance
     * @since 3.2.0
     */
    public static PemSslStoreDetails forCertificates(@Nullable String certificates) {
        return new PemSslStoreDetails(null, certificates, null);
    }
}

PemContent

Class for handling PEM-encoded content.

package org.springframework.boot.ssl.pem;

/**
 * PEM encoded content that can provide X509Certificate certificates and
 * PrivateKey private keys.
 *
 * @author Scott Frederick
 * @author Phillip Webb
 * @since 3.2.0
 */
public final class PemContent {

    /**
     * Parse and return all X509Certificate certificates from the PEM content.
     * Most PEM files either contain a single certificate or a certificate chain.
     *
     * @return the certificates
     * @throws IllegalStateException if no certificates could be loaded
     */
    public List<X509Certificate> getCertificates() {
        // Uses internal PemCertificateParser to extract X.509 certificates
        // Supports multiple certificate formats within PEM content
        // Returns immutable list of parsed certificates
    }

    /**
     * Parse and return the PrivateKey private keys from the PEM content.
     *
     * @return the private keys
     * @throws IllegalStateException if no private key could be loaded
     */
    public @Nullable PrivateKey getPrivateKey() {
        return getPrivateKey(null);
    }

    /**
     * Parse and return the PrivateKey private keys from the PEM content or
     * null if there is no private key.
     *
     * @param password the password to decrypt the private keys or null
     * @return the private keys
     */
    public @Nullable PrivateKey getPrivateKey(@Nullable String password) {
        // Uses internal PemPrivateKeyParser to extract private key
        // Supports PKCS#1 RSA, SEC1 EC, PKCS#8, and encrypted PKCS#8 formats
        // Supports RSA, EC, DSA, EdDSA, and XDH key algorithms
        // Handles encrypted keys using the provided password
    }

    /**
     * Load PemContent from the given Path.
     *
     * @param path a path to load the content from
     * @return the loaded PEM content
     * @throws IOException on IO error
     */
    public static PemContent load(Path path) throws IOException {
        try (InputStream in = Files.newInputStream(path, StandardOpenOption.READ)) {
            return load(in);
        }
    }

    /**
     * Load PemContent from the given InputStream.
     *
     * @param in an input stream to load the content from
     * @return the loaded PEM content
     * @throws IOException on IO error
     */
    public static PemContent load(InputStream in) throws IOException {
        // Reads stream to String using UTF-8 encoding
        return of(StreamUtils.copyToString(in, StandardCharsets.UTF_8));
    }

    /**
     * Return a new PemContent instance containing the given text.
     *
     * @param text the text containing PEM encoded content
     * @return a new PemContent instance
     */
    public static @Nullable PemContent of(@Nullable String text) {
        // Normalizes text by trimming lines and joining with newlines
        return (text != null) ? new PemContent(text) : null;
    }

    /**
     * Return if PEM content is present in the given text.
     *
     * @param text the text to check
     * @return if the text includes PEM encoded content
     */
    public static boolean isPresentInText(@Nullable String text) {
        // Checks for PEM header (BEGIN) and footer (END) markers using regex
        return text != null && PEM_HEADER.matcher(text).find()
                            && PEM_FOOTER.matcher(text).find();
    }
}

JKS Support

The org.springframework.boot.ssl.jks package provides support for Java KeyStore format.

JksSslStoreBundle

SslStoreBundle implementation for JKS keystores.

package org.springframework.boot.ssl.jks;

/**
 * SslStoreBundle backed by a Java keystore.
 *
 * @author Scott Frederick
 * @author Phillip Webb
 * @author Moritz Halbritter
 * @since 3.1.0
 */
public class JksSslStoreBundle implements SslStoreBundle {

    /**
     * Create a new JksSslStoreBundle instance.
     *
     * @param keyStoreDetails the key store details
     * @param trustStoreDetails the trust store details
     */
    public JksSslStoreBundle(JksSslStoreDetails keyStoreDetails,
                             JksSslStoreDetails trustStoreDetails) {
    }

    /**
     * Create a new JksSslStoreBundle instance.
     *
     * @param keyStoreDetails the key store details
     * @param trustStoreDetails the trust store details
     * @param resourceLoader the resource loader used to load content
     * @since 3.3.5
     */
    public JksSslStoreBundle(JksSslStoreDetails keyStoreDetails,
                             JksSslStoreDetails trustStoreDetails,
                             ResourceLoader resourceLoader) {
    }

    @Override
    public KeyStore getKeyStore() {
        // Returns KeyStore loaded from file or hardware store
    }

    @Override
    public String getKeyStorePassword() {
        // Returns password from details
    }

    @Override
    public KeyStore getTrustStore() {
        // Returns KeyStore loaded from file or hardware store
    }
}

JksSslStoreDetails

Configuration details for JKS-based stores.

package org.springframework.boot.ssl.jks;

/**
 * Details for an individual trust or key store in a JksSslStoreBundle.
 *
 * @param type the key store type, for example JKS or PKCS11. A null value
 *             will use KeyStore.getDefaultType()
 * @param provider the name of the key store provider
 * @param location the location of the key store file or null if using a
 *                 PKCS11 hardware store
 * @param password the password used to unlock the store or null
 * @author Scott Frederick
 * @author Phillip Webb
 * @since 3.1.0
 */
public record JksSslStoreDetails(@Nullable String type, @Nullable String provider,
                                 @Nullable String location, @Nullable String password) {

    /**
     * Return a new JksSslStoreDetails instance with a new password.
     *
     * @param password the new password
     * @return a new JksSslStoreDetails instance
     */
    public JksSslStoreDetails withPassword(String password) {
        return new JksSslStoreDetails(this.type, this.provider,
                                      this.location, password);
    }

    /**
     * Factory method to create a new JksSslStoreDetails instance for the given location.
     *
     * @param location the location
     * @return a new JksSslStoreDetails instance
     */
    public static JksSslStoreDetails forLocation(@Nullable String location) {
        return new JksSslStoreDetails(null, null, location, null);
    }
}

Exception Handling

NoSuchSslBundleException

Exception thrown when a requested SSL bundle cannot be found.

package org.springframework.boot.ssl;

/**
 * Exception indicating that an SslBundle was referenced with a name that does not
 * match any registered bundle.
 *
 * @author Scott Frederick
 * @since 3.1.0
 */
public class NoSuchSslBundleException extends RuntimeException {

    /**
     * Create a new NoSuchSslBundleException instance.
     *
     * @param bundleName the name of the bundle that could not be found
     * @param message the exception message
     */
    public NoSuchSslBundleException(String bundleName, String message) {
        this(bundleName, message, null);
    }

    /**
     * Create a new NoSuchSslBundleException instance.
     *
     * @param bundleName the name of the bundle that could not be found
     * @param message the exception message
     * @param cause the exception cause
     */
    public NoSuchSslBundleException(String bundleName, String message, @Nullable Throwable cause) {
        super(message, cause);
        this.bundleName = bundleName;
    }

    /**
     * Return the name of the bundle that was not found.
     *
     * @return the bundle name
     */
    public String getBundleName() {
        return this.bundleName;
    }
}

Implementation Details

Internal Support Classes

The SSL/TLS bundle management system uses several internal (package-private) implementation classes that are not part of the public API but are important for understanding the system architecture:

DefaultSslManagerBundle

Internal implementation of SslManagerBundle that creates KeyManagerFactory and TrustManagerFactory instances from an SslStoreBundle and SslBundleKey. This class is used by the SslManagerBundle.from(SslStoreBundle, SslBundleKey) static factory method.

LoadedPemSslStore

Internal implementation of PemSslStore that lazily loads PEM content from PemSslStoreDetails using a ResourceLoader. This class is used by PemSslStore.load() methods.

PemCertificateParser

Internal utility for parsing X.509 certificates from PEM-encoded text. It:

  • Uses regex patterns to locate certificate blocks (BEGIN/END CERTIFICATE markers)
  • Decodes Base64 content
  • Creates X509Certificate instances using CertificateFactory
  • Returns immutable lists of certificates

PemPrivateKeyParser

Internal utility for parsing private keys from PEM-encoded text. It supports:

  • PKCS#1 RSA format: Traditional RSA private key format
  • SEC1 EC format: Elliptic curve private key format
  • PKCS#8 format: Standard private key format for multiple algorithms
  • PKCS#8 Encrypted: Password-protected private keys using PBES2 encryption
  • Key algorithms: RSA, RSASSA-PSS, EC, DSA, EdDSA, and XDH

The parser handles:

  • ASN.1 DER encoding/decoding
  • Algorithm identification via OIDs
  • Password-based encryption/decryption
  • Conversion to PKCS#8 format for older formats

AliasKeyManagerFactory

Internal KeyManagerFactory wrapper that filters keys by alias. When an alias is specified in SslBundleKey, this factory wraps the standard KeyManagerFactory with an X509ExtendedKeyManager that always returns the specified alias for server operations.

FixedTrustManagerFactory

Internal TrustManagerFactory implementation that uses a fixed set of TrustManager instances. This is used by SslManagerBundle.from(TrustManager...) to create a bundle with custom trust managers while using default key managers.

PEM Format Support

The PEM support automatically detects and handles:

  • Certificate chains: Multiple certificates in sequence
  • Individual certificates: Single certificate entries
  • Private keys: Various PKCS formats with automatic conversion
  • Encrypted keys: PKCS#8 encrypted format with password decryption
  • Mixed content: Files containing both certificates and private keys
  • Resource references: Classpath, file system, and inline PEM content

JKS Format Support

The JKS support handles:

  • Standard KeyStores: JKS, PKCS12, and other Java KeyStore formats
  • Hardware keystores: PKCS11 hardware security module support
  • Custom providers: Pluggable security provider support
  • Resource loading: File system and classpath resource loading

Usage Examples

Basic PEM Configuration

// Create PEM store details
PemSslStoreDetails keyStoreDetails = new PemSslStoreDetails(
    null,  // type (use default)
    "classpath:certs/server-cert.pem",  // certificate
    "classpath:certs/server-key.pem",   // private key
    "key-password"  // private key password
);

PemSslStoreDetails trustStoreDetails =
    PemSslStoreDetails.forCertificate("classpath:certs/ca-cert.pem");

// Create SSL store bundle
PemSslStoreBundle storeBundle = new PemSslStoreBundle(
    keyStoreDetails,
    trustStoreDetails
);

// Create SSL bundle with options
SslBundleKey key = SslBundleKey.of("key-password");
SslOptions options = SslOptions.of(
    new String[]{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"},
    new String[]{"TLSv1.2", "TLSv1.3"}
);

SslBundle sslBundle = SslBundle.of(storeBundle, key, options, "TLS");

// Create SSL context
SSLContext sslContext = sslBundle.createSslContext();

JKS Configuration

// Create JKS store details
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(
    "JKS",  // type
    null,   // provider (use default)
    "classpath:keystore.jks",  // location
    "store-password"  // password
);

JksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(
    "classpath:truststore.jks"
);

// Create SSL store bundle
JksSslStoreBundle storeBundle = new JksSslStoreBundle(
    keyStoreDetails,
    trustStoreDetails
);

// Create SSL bundle
SslBundleKey key = SslBundleKey.of("key-password", "server-key");
SslBundle sslBundle = SslBundle.of(storeBundle, key);

Using SSL Bundle Registry

// Create and register bundles
DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();

// Register PEM bundle
PemSslStoreBundle pemStore = new PemSslStoreBundle(
    pemKeyStoreDetails,
    pemTrustStoreDetails
);
registry.registerBundle("pem-bundle", SslBundle.of(pemStore));

// Register JKS bundle
JksSslStoreBundle jksStore = new JksSslStoreBundle(
    jksKeyStoreDetails,
    jksTrustStoreDetails
);
registry.registerBundle("jks-bundle", SslBundle.of(jksStore));

// Retrieve and use bundle
SslBundle bundle = registry.getBundle("pem-bundle");
SSLContext context = bundle.createSslContext();

// Add update handler
registry.addBundleUpdateHandler("pem-bundle", updatedBundle -> {
    System.out.println("Bundle updated!");
    // Reinitialize SSL connections with updated bundle
});

Loading PEM Content Directly

// Load from file
PemContent pemContent = PemContent.load(Path.of("/path/to/cert.pem"));
List<X509Certificate> certificates = pemContent.getCertificates();
PrivateKey privateKey = pemContent.getPrivateKey("password");

// Load from string
String pemText = """
    -----BEGIN CERTIFICATE-----
    MIIDXTCCAkWgAwIBAgIJAKZP...
    -----END CERTIFICATE-----
    """;
PemContent content = PemContent.of(pemText);
List<X509Certificate> certs = content.getCertificates();

// Check if text contains PEM content
boolean hasPem = PemContent.isPresentInText(pemText);

Dynamic Bundle Updates

DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();

// Register initial bundle
SslBundle initialBundle = SslBundle.of(initialStoreBundle);
registry.registerBundle("dynamic-bundle", initialBundle);

// Add update handler to components using the bundle
registry.addBundleUpdateHandler("dynamic-bundle", updatedBundle -> {
    // Update Tomcat connector
    tomcatConnector.setSslContext(updatedBundle.createSslContext());

    // Update other SSL components
    sslClient.updateContext(updatedBundle.createSslContext());
});

// Later, update the bundle (e.g., after certificate renewal)
PemSslStoreBundle newStoreBundle = new PemSslStoreBundle(
    newKeyStoreDetails,
    newTrustStoreDetails
);
SslBundle updatedBundle = SslBundle.of(newStoreBundle);
registry.updateBundle("dynamic-bundle", updatedBundle);
// All registered handlers are automatically called

Custom SSL Configuration

// Create custom SSL options
SslOptions customOptions = SslOptions.of(
    new String[]{
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
    },
    new String[]{"TLSv1.3"}
);

// Create bundle key with specific alias
SslBundleKey bundleKey = SslBundleKey.of("key-password", "my-server");

// Create complete bundle
SslBundle customBundle = SslBundle.of(
    storeBundle,      // Store bundle (PEM or JKS)
    bundleKey,        // Key reference
    customOptions,    // SSL options
    "TLSv1.3"        // Protocol
);

// Use with custom manager bundle
SslManagerBundle managerBundle = SslManagerBundle.from(storeBundle, bundleKey);
SslBundle bundleWithManagers = SslBundle.of(
    storeBundle,
    bundleKey,
    customOptions,
    "TLSv1.3",
    managerBundle
);

Working with PemSslStore

// Create PEM store programmatically
List<X509Certificate> certificates = loadCertificates();
PrivateKey privateKey = loadPrivateKey();

PemSslStore pemStore = PemSslStore.of(certificates, privateKey);

// Customize store
PemSslStore customStore = pemStore
    .withAlias("my-server")
    .withPassword("store-password");

// Create bundle from store
PemSslStoreBundle bundle = new PemSslStoreBundle(customStore, null);
KeyStore keyStore = bundle.getKeyStore();

Hardware KeyStore (PKCS11)

// Configure hardware keystore
JksSslStoreDetails hardwareDetails = new JksSslStoreDetails(
    "PKCS11",          // type
    "SunPKCS11",       // provider
    null,              // location (null for hardware)
    "pin-password"     // password/PIN
);

JksSslStoreBundle hardwareBundle = new JksSslStoreBundle(
    hardwareDetails,
    null  // trust store
);

// Use hardware key
SslBundleKey hardwareKey = SslBundleKey.of("pin-password", "hardware-key-alias");
SslBundle bundle = SslBundle.of(hardwareBundle, hardwareKey);

Type Definitions

Complete SslBundle Structure

public interface SslBundle {
    SslStoreBundle getStores();      // Key and trust stores
    SslBundleKey getKey();           // Key reference
    SslOptions getOptions();         // Cipher and protocol options
    String getProtocol();            // SSL protocol (e.g., "TLS")
    SslManagerBundle getManagers();  // Key and trust managers
    SSLContext createSslContext();   // Creates ready-to-use SSLContext
}

Store Bundle Hierarchy

SslStoreBundle (interface)
    ├── PemSslStoreBundle (class)
    │   └── Uses PemSslStore/PemSslStoreDetails
    └── JksSslStoreBundle (class)
        └── Uses JksSslStoreDetails

Manager Bundle Structure

public interface SslManagerBundle {
    KeyManagerFactory getKeyManagerFactory();
    KeyManager[] getKeyManagers();
    TrustManagerFactory getTrustManagerFactory();
    TrustManager[] getTrustManagers();
    SSLContext createSslContext(String protocol);
}

PEM Content Flow

PemSslStoreDetails (configuration)
    ↓
PemSslStore (loaded content)
    ↓
PemContent (parsed PEM)
    ├→ PemCertificateParser → List<X509Certificate>
    └→ PemPrivateKeyParser → PrivateKey

Key Features

  1. Unified API: Single API works with both PEM and JKS formats
  2. Dynamic Updates: Support for runtime certificate updates with callback handlers
  3. Hardware Support: PKCS11 hardware keystore support
  4. Format Flexibility: Automatic detection and parsing of various PEM formats
  5. Type Safety: Record types for configuration with immutable properties
  6. Resource Loading: Supports loading from classpath, filesystem, and inline content
  7. Password Protection: Full support for encrypted private keys
  8. Protocol Control: Fine-grained control over SSL protocols and ciphers
  9. System Defaults: Easy access to system default SSL configuration
  10. Thread-Safe: Thread-safe bundle registry with concurrent updates

Common Patterns

Pattern 1: Microservice Mutual TLS (mTLS) Configuration

Configure both server and client certificates for mutual authentication between microservices.

import org.springframework.boot.ssl.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;

@Configuration
public class MutualTlsConfiguration {

    @Bean
    public SslBundleRegistry sslBundleRegistry() {
        DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();

        // Server bundle with server certificate and CA trust
        PemSslStoreDetails serverKeyStore = PemSslStoreDetails.forCertificate(
            "classpath:certs/server-cert.pem")
            .withPrivateKey("classpath:certs/server-key.pem")
            .withPrivateKeyPassword("server-key-password");

        PemSslStoreDetails serverTrustStore = PemSslStoreDetails.forCertificate(
            "classpath:certs/ca-cert.pem");

        PemSslStoreBundle serverStoreBundle = new PemSslStoreBundle(
            serverKeyStore, serverTrustStore);

        // Require client authentication
        SslOptions serverOptions = SslOptions.of(
            new String[]{
                "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
                "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
            },
            new String[]{"TLSv1.3", "TLSv1.2"}
        );

        SslBundle serverBundle = SslBundle.of(
            serverStoreBundle,
            SslBundleKey.of("server-key-password"),
            serverOptions,
            "TLSv1.3"
        );

        registry.registerBundle("server", serverBundle);

        // Client bundle with client certificate and CA trust
        PemSslStoreDetails clientKeyStore = PemSslStoreDetails.forCertificate(
            "classpath:certs/client-cert.pem")
            .withPrivateKey("classpath:certs/client-key.pem")
            .withPrivateKeyPassword("client-key-password");

        PemSslStoreDetails clientTrustStore = PemSslStoreDetails.forCertificate(
            "classpath:certs/ca-cert.pem");

        PemSslStoreBundle clientStoreBundle = new PemSslStoreBundle(
            clientKeyStore, clientTrustStore);

        SslBundle clientBundle = SslBundle.of(clientStoreBundle,
            SslBundleKey.of("client-key-password"));

        registry.registerBundle("client", clientBundle);

        return registry;
    }

    @Bean
    public SSLContext serverSslContext(SslBundleRegistry registry) {
        return registry.getBundle("server").createSslContext();
    }

    @Bean
    public SSLContext clientSslContext(SslBundleRegistry registry) {
        return registry.getBundle("client").createSslContext();
    }
}

Use Cases:

  • Service-to-service authentication in microservices
  • Zero-trust security architectures
  • API gateway to backend service communication

Pattern 2: Automatic Certificate Rotation with Let's Encrypt

Implement automatic certificate renewal and hot-reload without service restart.

import org.springframework.boot.ssl.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;

@Component
public class CertificateRotationService {

    private static final Logger log = LoggerFactory.getLogger(CertificateRotationService.class);

    private final SslBundleRegistry registry;
    private final Path certPath = Path.of("/etc/letsencrypt/live/example.com/cert.pem");
    private final Path keyPath = Path.of("/etc/letsencrypt/live/example.com/privkey.pem");
    private final Path chainPath = Path.of("/etc/letsencrypt/live/example.com/chain.pem");

    private FileTime lastModified;

    public CertificateRotationService(SslBundleRegistry registry) {
        this.registry = registry;
        initializeBundle();
        setupUpdateHandlers();
    }

    private void initializeBundle() {
        try {
            SslBundle initialBundle = createBundleFromFiles();
            registry.registerBundle("letsencrypt", initialBundle);
            lastModified = Files.getLastModifiedTime(certPath);
            log.info("Initialized SSL bundle from Let's Encrypt certificates");
        } catch (Exception e) {
            log.error("Failed to initialize SSL bundle", e);
            throw new IllegalStateException("SSL initialization failed", e);
        }
    }

    private void setupUpdateHandlers() {
        registry.addBundleUpdateHandler("letsencrypt", updatedBundle -> {
            log.info("Certificate rotation detected - updating SSL context");
            // Update embedded server
            updateEmbeddedServer(updatedBundle);
            // Update HTTP clients
            updateHttpClients(updatedBundle);
            log.info("SSL context updated successfully");
        });
    }

    @Scheduled(fixedRate = 3600000) // Check every hour
    public void checkForCertificateUpdates() {
        try {
            FileTime currentModified = Files.getLastModifiedTime(certPath);

            if (currentModified.compareTo(lastModified) > 0) {
                log.info("Certificate file updated - reloading");
                SslBundle updatedBundle = createBundleFromFiles();
                registry.updateBundle("letsencrypt", updatedBundle);
                lastModified = currentModified;
                log.info("Certificate rotation completed");
            }
        } catch (Exception e) {
            log.error("Failed to check for certificate updates", e);
        }
    }

    private SslBundle createBundleFromFiles() throws Exception {
        PemSslStoreDetails keyStore = PemSslStoreDetails
            .forCertificate(certPath.toString())
            .withPrivateKey(keyPath.toString());

        PemSslStoreDetails trustStore = PemSslStoreDetails
            .forCertificate(chainPath.toString());

        PemSslStoreBundle storeBundle = new PemSslStoreBundle(keyStore, trustStore);

        return SslBundle.of(storeBundle);
    }

    private void updateEmbeddedServer(SslBundle bundle) {
        // Implementation specific to embedded server (Tomcat, Jetty, etc.)
    }

    private void updateHttpClients(SslBundle bundle) {
        // Update RestTemplate, WebClient, etc.
    }
}

Use Cases:

  • Automated Let's Encrypt certificate renewal
  • Certificate rotation without downtime
  • Dynamic SSL configuration in cloud environments

Pattern 3: Multi-Environment SSL Configuration

Manage different SSL configurations across development, staging, and production environments.

import org.springframework.boot.ssl.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;

@Configuration
public class EnvironmentSpecificSslConfig {

    @Bean
    @Profile("development")
    public SslBundleRegistry developmentSslRegistry() {
        DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();

        // Use self-signed certificate for development
        PemSslStoreDetails devKeyStore = PemSslStoreDetails
            .forCertificate("classpath:dev-certs/localhost.pem")
            .withPrivateKey("classpath:dev-certs/localhost-key.pem");

        PemSslStoreBundle devBundle = new PemSslStoreBundle(devKeyStore, null);
        SslBundle bundle = SslBundle.of(devBundle);

        registry.registerBundle("default", bundle);
        return registry;
    }

    @Bean
    @Profile("staging")
    public SslBundleRegistry stagingSslRegistry() {
        DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();

        // Use staging certificate authority
        PemSslStoreDetails stagingKeyStore = PemSslStoreDetails
            .forCertificate("classpath:staging-certs/cert.pem")
            .withPrivateKey("classpath:staging-certs/key.pem");

        PemSslStoreDetails stagingTrustStore = PemSslStoreDetails
            .forCertificate("classpath:staging-certs/staging-ca.pem");

        PemSslStoreBundle storeBundle = new PemSslStoreBundle(
            stagingKeyStore, stagingTrustStore);

        // More relaxed SSL options for staging
        SslOptions stagingOptions = SslOptions.of(
            new String[]{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"},
            new String[]{"TLSv1.2"}
        );

        SslBundle bundle = SslBundle.of(storeBundle, null, stagingOptions);
        registry.registerBundle("default", bundle);
        return registry;
    }

    @Bean
    @Profile("production")
    public SslBundleRegistry productionSslRegistry(Environment env) {
        DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();

        // Load from secure external configuration
        String certLocation = env.getRequiredProperty("ssl.certificate.location");
        String keyLocation = env.getRequiredProperty("ssl.key.location");
        String keyPassword = env.getRequiredProperty("ssl.key.password");
        String trustLocation = env.getRequiredProperty("ssl.trust.location");

        PemSslStoreDetails keyStore = PemSslStoreDetails
            .forCertificate(certLocation)
            .withPrivateKey(keyLocation)
            .withPrivateKeyPassword(keyPassword);

        PemSslStoreDetails trustStore = PemSslStoreDetails
            .forCertificate(trustLocation);

        PemSslStoreBundle storeBundle = new PemSslStoreBundle(keyStore, trustStore);

        // Strict SSL options for production
        SslOptions productionOptions = SslOptions.of(
            new String[]{
                "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
                "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
                "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
                "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
            },
            new String[]{"TLSv1.3"}
        );

        SslBundle bundle = SslBundle.of(
            storeBundle,
            SslBundleKey.of(keyPassword),
            productionOptions,
            "TLSv1.3"
        );

        registry.registerBundle("default", bundle);
        return registry;
    }
}

Use Cases:

  • Environment-specific security policies
  • Development with self-signed certificates
  • Production with enterprise CA certificates

Pattern 4: Hardware Security Module (HSM) Integration

Use hardware security modules for private key storage in high-security environments.

import org.springframework.boot.ssl.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.KeyManagerFactory;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;

@Configuration
public class HsmSslConfiguration {

    @Bean
    public SslBundleRegistry hsmSslRegistry() throws Exception {
        // Load PKCS11 provider for HSM
        String pkcs11Config = """
            name = HSM
            library = /usr/lib/libpkcs11.so
            slot = 0
            """;

        Provider hsm Provider = Security.getProvider("SunPKCS11");
        hsmProvider = hsmProvider.configure(pkcs11Config);
        Security.addProvider(hsmProvider);

        // Create JKS bundle for HSM
        JksSslStoreDetails hsmKeyStore = new JksSslStoreDetails(
            "PKCS11",           // type
            "SunPKCS11",        // provider
            null,               // location (null for hardware)
            "hsm-pin"           // HSM PIN
        );

        // Regular trust store from file
        JksSslStoreDetails trustStore = new JksSslStoreDetails(
            "JKS",
            null,
            "classpath:truststore.jks",
            "trust-password"
        );

        JksSslStoreBundle storeBundle = new JksSslStoreBundle(
            hsmKeyStore, trustStore);

        // Key is stored in HSM with alias
        SslBundleKey bundleKey = SslBundleKey.of("hsm-pin", "production-key");

        // Create bundle
        SslBundle hsmBundle = SslBundle.of(storeBundle, bundleKey);

        DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();
        registry.registerBundle("hsm", hsmBundle);

        return registry;
    }

    @Bean
    public KeyManagerFactory hsmKeyManagerFactory(SslBundleRegistry registry) {
        SslBundle bundle = registry.getBundle("hsm");
        return bundle.getManagers().getKeyManagerFactory();
    }
}

Use Cases:

  • Financial services requiring FIPS 140-2 compliance
  • Government systems with hardware security requirements
  • High-value transaction processing

Pattern 5: Certificate Chain Validation and Monitoring

Implement comprehensive certificate monitoring with expiration alerts.

import org.springframework.boot.ssl.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

@Component
public class CertificateMonitoringService {

    private static final Logger log = LoggerFactory.getLogger(CertificateMonitoringService.class);
    private static final Duration WARNING_THRESHOLD = Duration.ofDays(30);
    private static final Duration CRITICAL_THRESHOLD = Duration.ofDays(7);

    private final SslBundleRegistry registry;

    public CertificateMonitoringService(SslBundleRegistry registry) {
        this.registry = registry;
    }

    @Scheduled(cron = "0 0 2 * * *") // Daily at 2 AM
    public void monitorCertificates() {
        log.info("Starting certificate monitoring check");

        try {
            SslBundle bundle = registry.getBundle("default");
            validateCertificateChain(bundle);
        } catch (NoSuchSslBundleException e) {
            log.error("SSL bundle 'default' not found", e);
        } catch (Exception e) {
            log.error("Certificate monitoring failed", e);
        }
    }

    private void validateCertificateChain(SslBundle bundle) throws Exception {
        KeyStore keyStore = bundle.getStores().getKeyStore();
        if (keyStore == null) {
            log.warn("No key store available for certificate monitoring");
            return;
        }

        Enumeration<String> aliases = keyStore.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            Certificate[] chain = keyStore.getCertificateChain(alias);

            if (chain == null) {
                continue;
            }

            log.info("Checking certificate chain for alias: {}", alias);

            for (int i = 0; i < chain.length; i++) {
                if (chain[i] instanceof X509Certificate x509) {
                    checkCertificateExpiration(alias, i, x509);
                    validateCertificateProperties(alias, i, x509);
                }
            }
        }
    }

    private void checkCertificateExpiration(String alias, int position,
                                           X509Certificate cert) {
        Instant now = Instant.now();
        Instant notAfter = cert.getNotAfter().toInstant();
        Duration timeUntilExpiry = Duration.between(now, notAfter);

        if (timeUntilExpiry.isNegative()) {
            log.error("EXPIRED: Certificate '{}' position {} expired on {}",
                alias, position, cert.getNotAfter());
            sendAlert(AlertLevel.CRITICAL, alias, cert, "Certificate expired");
        } else if (timeUntilExpiry.compareTo(CRITICAL_THRESHOLD) < 0) {
            log.error("CRITICAL: Certificate '{}' position {} expires in {} days",
                alias, position, timeUntilExpiry.toDays());
            sendAlert(AlertLevel.CRITICAL, alias, cert,
                "Certificate expiring in " + timeUntilExpiry.toDays() + " days");
        } else if (timeUntilExpiry.compareTo(WARNING_THRESHOLD) < 0) {
            log.warn("WARNING: Certificate '{}' position {} expires in {} days",
                alias, position, timeUntilExpiry.toDays());
            sendAlert(AlertLevel.WARNING, alias, cert,
                "Certificate expiring in " + timeUntilExpiry.toDays() + " days");
        } else {
            log.debug("Certificate '{}' position {} valid until {}",
                alias, position, cert.getNotAfter());
        }
    }

    private void validateCertificateProperties(String alias, int position,
                                              X509Certificate cert) {
        // Check key size
        int keySize = cert.getPublicKey().getEncoded().length * 8;
        if (keySize < 2048) {
            log.warn("Weak key size {} for certificate '{}' position {}",
                keySize, alias, position);
        }

        // Check signature algorithm
        String sigAlg = cert.getSigAlgName();
        if (sigAlg.contains("SHA1") || sigAlg.contains("MD5")) {
            log.warn("Weak signature algorithm {} for certificate '{}' position {}",
                sigAlg, alias, position);
        }

        // Log certificate details
        log.info("Certificate '{}' position {}: Subject={}, Issuer={}, Valid until={}",
            alias, position, cert.getSubjectX500Principal(),
            cert.getIssuerX500Principal(), cert.getNotAfter());
    }

    private void sendAlert(AlertLevel level, String alias,
                          X509Certificate cert, String message) {
        // Integrate with alerting system (PagerDuty, Slack, email, etc.)
        log.info("Sending {} alert: {} for certificate {}",
            level, message, alias);
    }

    enum AlertLevel {
        WARNING, CRITICAL
    }
}

Use Cases:

  • Preventing certificate expiration outages
  • Compliance audit trails
  • Proactive certificate lifecycle management

Best Practices

SSL Configuration

  1. Use Bundle Registry: Central management of all SSL bundles
  2. Implement Update Handlers: Handle certificate rotation gracefully
  3. Specify Protocols: Explicitly configure allowed SSL/TLS versions (TLSv1.3, TLSv1.2 minimum)
  4. Secure Passwords: Never hardcode passwords in source code - use environment variables or secret managers
  5. Validate Aliases: Use assertContainsAlias() to verify key aliases exist before deployment
  6. Resource Paths: Use Spring resource prefixes (classpath:, file:, etc.) for portability
  7. Test Configurations: Validate SSL bundles before production deployment with integration tests
  8. Monitor Updates: Log bundle update events for audit trails and compliance
  9. Handle Exceptions: Always catch NoSuchSslBundleException and provide fallback behavior
  10. Use System Defaults: Consider SslBundle.systemDefault() for standard cases

Security Best Practices

  1. Disable Weak Ciphers: Explicitly configure strong cipher suites (AES-256-GCM, ChaCha20-Poly1305)
  2. Enforce TLS 1.3: Use TLSv1.3 in production when possible, minimum TLSv1.2
  3. Validate Certificate Chains: Always configure trust stores with CA certificates
  4. Key Size Requirements: Use minimum 2048-bit RSA or 256-bit ECC keys
  5. Certificate Expiration: Monitor certificates and rotate 30 days before expiration
  6. Private Key Protection: Use encrypted private keys with strong passwords
  7. Mutual TLS: Implement client certificate authentication for service-to-service communication
  8. Audit Logging: Log all SSL configuration changes and certificate updates

Certificate Management

  1. Automate Rotation: Implement automated certificate renewal (e.g., Let's Encrypt, cert-manager)
  2. Test Before Deploy: Validate certificate chains and expiration dates before deployment
  3. Backup Certificates: Maintain secure backups of certificates and private keys
  4. Certificate Inventory: Keep inventory of all certificates with expiration tracking
  5. Rollback Plan: Have procedure to revert to previous certificates if issues occur

Performance Considerations

  1. Connection Pooling: Reuse SSLContext instances - they are expensive to create
  2. Session Caching: Enable SSL session caching for improved performance
  3. Hardware Acceleration: Use hardware security modules (HSM) for high-throughput scenarios
  4. Lazy Loading: PEM parsing is done on first access - preload for critical paths

Error Handling

@Component
public class RobustSslConfiguration {

    private final SslBundleRegistry registry;

    public RobustSslConfiguration(SslBundleRegistry registry) {
        this.registry = registry;
    }

    public SSLContext getSslContext(String bundleName) {
        try {
            SslBundle bundle = registry.getBundle(bundleName);
            return bundle.createSslContext();
        } catch (NoSuchSslBundleException e) {
            log.error("SSL bundle '{}' not found, using system default", bundleName, e);
            return SslBundle.systemDefault().createSslContext();
        } catch (Exception e) {
            log.error("Failed to create SSL context", e);
            throw new IllegalStateException("SSL configuration failed", e);
        }
    }
}

Common Pitfalls to Avoid

  1. Don't ignore certificate expiration - Set up monitoring and alerts
  2. Don't use self-signed certs in production - Use proper CA-signed certificates
  3. Don't hardcode file paths - Use Spring resource abstraction
  4. Don't skip trust store validation - Always validate server certificates
  5. Don't reuse passwords across environments - Use different passwords for dev/staging/prod
  6. Don't skip testing certificate rotation - Test hot-reload before incidents occur
  7. Don't expose private keys in logs - Sanitize logging of SSL configuration
  8. Don't use deprecated algorithms - Avoid MD5, SHA-1, RC4, DES
  9. Don't forget OCSP/CRL - Consider certificate revocation checking for high-security applications
  10. Don't mix PEM formats - Be consistent with PKCS#1 vs PKCS#8 private key formats

PEM SSL Support (ssl.pem Package)

The org.springframework.boot.ssl.pem package provides comprehensive support for PEM-encoded SSL/TLS certificates and private keys.

PemContent

Represents PEM-encoded content that can provide X.509 certificates and private keys.

package org.springframework.boot.ssl.pem;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.List;

/**
 * PEM encoded content that can provide X509Certificate certificates and PrivateKey private keys.
 *
 * Thread Safety: Immutable and thread-safe after construction.
 *
 * @since 3.2.0
 */
public final class PemContent {

    /**
     * Parse and return all X509Certificate certificates from the PEM content.
     * Most PEM files either contain a single certificate or a certificate chain.
     *
     * @return the certificates
     * @throws IllegalStateException if no certificates could be loaded
     */
    public List<X509Certificate> getCertificates();

    /**
     * Parse and return the PrivateKey from the PEM content.
     *
     * @return the private key or null
     * @throws IllegalStateException if no private key could be loaded
     */
    public @Nullable PrivateKey getPrivateKey();

    /**
     * Parse and return the PrivateKey from the PEM content with password decryption.
     *
     * @param password the password to decrypt the private key or null
     * @return the private key or null
     */
    public @Nullable PrivateKey getPrivateKey(@Nullable String password);

    /**
     * Load PemContent from the given Path.
     *
     * @param path a path to load the content from
     * @return the loaded PEM content
     * @throws IOException on IO error
     */
    public static PemContent load(Path path) throws IOException;

    /**
     * Load PemContent from the given InputStream.
     *
     * @param in an input stream to load the content from
     * @return the loaded PEM content
     * @throws IOException on IO error
     */
    public static PemContent load(InputStream in) throws IOException;

    /**
     * Return a new PemContent instance containing the given text.
     *
     * @param text the text containing PEM encoded content
     * @return a new PemContent instance
     */
    public static @Nullable PemContent of(@Nullable String text);

    /**
     * Return if PEM content is present in the given text.
     *
     * @param text the text to check
     * @return true if the text includes PEM encoded content
     */
    public static boolean isPresentInText(@Nullable String text);
}

PemSslStore

An individual trust or key store loaded from PEM content.

package org.springframework.boot.ssl.pem;

import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.List;

/**
 * An individual trust or key store that has been loaded from PEM content.
 *
 * Thread Safety: Immutable and thread-safe.
 *
 * @since 3.2.0
 */
public interface PemSslStore {

    /**
     * The key store type, for example JKS or PKCS11. A null value will use KeyStore.getDefaultType().
     *
     * @return the key store type
     */
    @Nullable String type();

    /**
     * The alias used when setting entries in the KeyStore.
     *
     * @return the alias
     */
    @Nullable String alias();

    /**
     * The password used when setting key entries in the KeyStore.
     *
     * @return the password
     */
    @Nullable String password();

    /**
     * The certificates for this store. When a private key is present the returned value is treated
     * as a certificate chain, otherwise it is treated as a list of certificates that should all be registered.
     *
     * @return the X509 certificates
     */
    @Nullable List<X509Certificate> certificates();

    /**
     * The private key for this store or null.
     *
     * @return the private key
     */
    @Nullable PrivateKey privateKey();

    /**
     * Return a new PemSslStore instance with a new alias.
     *
     * @param alias the new alias
     * @return a new PemSslStore instance
     */
    default PemSslStore withAlias(@Nullable String alias);

    /**
     * Return a new PemSslStore instance with a new password.
     *
     * @param password the new password
     * @return a new PemSslStore instance
     */
    default PemSslStore withPassword(@Nullable String password);

    /**
     * Return a PemSslStore instance loaded using the given PemSslStoreDetails.
     *
     * @param details the PEM store details
     * @return a loaded PemSslStore or null
     */
    static @Nullable PemSslStore load(@Nullable PemSslStoreDetails details);

    /**
     * Factory method to create a new PemSslStore with the given values.
     *
     * @param type the key store type
     * @param certificates the certificates for this store
     * @param privateKey the private key
     * @return a new PemSslStore instance
     */
    static PemSslStore of(@Nullable String type, List<X509Certificate> certificates, @Nullable PrivateKey privateKey);
}

PemSslStoreDetails

Details for configuring an individual trust or key store from PEM content.

package org.springframework.boot.ssl.pem;

/**
 * Details for an individual trust or key store in a PemSslStoreBundle.
 *
 * Thread Safety: Immutable record, thread-safe.
 *
 * @since 3.1.0
 */
public record PemSslStoreDetails(
    @Nullable String type,
    @Nullable String alias,
    @Nullable String password,
    @Nullable String certificates,
    @Nullable String privateKey,
    @Nullable String privateKeyPassword
) {

    /**
     * Return a new PemSslStoreDetails instance with a new alias.
     *
     * @param alias the new alias
     * @return a new PemSslStoreDetails instance
     */
    public PemSslStoreDetails withAlias(@Nullable String alias);

    /**
     * Return a new PemSslStoreDetails instance with a new password.
     *
     * @param password the new password
     * @return a new PemSslStoreDetails instance
     */
    public PemSslStoreDetails withPassword(@Nullable String password);

    /**
     * Return a new PemSslStoreDetails instance with a new private key.
     *
     * @param privateKey the new private key
     * @return a new PemSslStoreDetails instance
     */
    public PemSslStoreDetails withPrivateKey(@Nullable String privateKey);

    /**
     * Factory method to create a new PemSslStoreDetails instance for the given certificates.
     *
     * @param certificates the certificates content (either the PEM content itself or a reference to the resource to load)
     * @return a new PemSslStoreDetails instance
     */
    public static PemSslStoreDetails forCertificates(@Nullable String certificates);
}

PemSslStoreBundle

SslStoreBundle backed by PEM-encoded certificates and private keys.

package org.springframework.boot.ssl.pem;

import org.springframework.boot.ssl.SslStoreBundle;

/**
 * SslStoreBundle backed by PEM-encoded certificates and private keys.
 *
 * Thread Safety: Thread-safe. Lazy-loads KeyStore instances on first access.
 *
 * @since 3.1.0
 */
public class PemSslStoreBundle implements SslStoreBundle {

    /**
     * Create a new PemSslStoreBundle instance.
     *
     * @param keyStoreDetails the key store details
     * @param trustStoreDetails the trust store details
     */
    public PemSslStoreBundle(@Nullable PemSslStoreDetails keyStoreDetails, @Nullable PemSslStoreDetails trustStoreDetails);

    /**
     * Create a new PemSslStoreBundle instance.
     *
     * @param pemKeyStore the PEM key store
     * @param pemTrustStore the PEM trust store
     */
    public PemSslStoreBundle(@Nullable PemSslStore pemKeyStore, @Nullable PemSslStore pemTrustStore);

    @Override
    public @Nullable KeyStore getKeyStore();

    @Override
    public @Nullable String getKeyStorePassword();

    @Override
    public @Nullable KeyStore getTrustStore();
}

PemCertificateParser

Parser for X.509 certificates in PEM format (internal utility).

package org.springframework.boot.ssl.pem;

/**
 * Parser for X.509 certificates in PEM format.
 * Internal utility class for parsing PEM-encoded certificates.
 *
 * Supports standard PEM format with BEGIN/END CERTIFICATE markers.
 *
 * Thread Safety: Stateless utility, thread-safe.
 */
final class PemCertificateParser {
    // Internal implementation - parses PEM certificates from text
}

PemPrivateKeyParser

Parser for PKCS private key files in PEM format (internal utility).

package org.springframework.boot.ssl.pem;

/**
 * Parser for PKCS private key files in PEM format.
 * Internal utility class for parsing PEM-encoded private keys.
 *
 * Supports multiple formats:
 * - PKCS#1 RSA private keys (BEGIN RSA PRIVATE KEY)
 * - PKCS#8 private keys (BEGIN PRIVATE KEY)
 * - PKCS#8 encrypted private keys (BEGIN ENCRYPTED PRIVATE KEY)
 * - SEC1 EC private keys (BEGIN EC PRIVATE KEY)
 *
 * Algorithms supported: RSA, RSASSA-PSS, EC, DSA, EdDSA, XDH
 *
 * Thread Safety: Stateless utility, thread-safe.
 */
final class PemPrivateKeyParser {
    // Internal implementation - parses various PEM private key formats
}

LoadedPemSslStore

Internal implementation of PemSslStore that lazy-loads content (internal class).

JKS SSL Support (ssl.jks Package)

The org.springframework.boot.ssl.jks package provides support for Java KeyStore (JKS) based SSL/TLS configuration.

JksSslStoreDetails

Details for configuring an individual trust or key store from a JKS file.

package org.springframework.boot.ssl.jks;

/**
 * Details for an individual trust or key store in a JksSslStoreBundle.
 *
 * Thread Safety: Immutable record, thread-safe.
 *
 * @since 3.1.0
 */
public record JksSslStoreDetails(
    @Nullable String type,
    @Nullable String provider,
    @Nullable String location,
    @Nullable String password
) {

    /**
     * Return a new JksSslStoreDetails instance with a new password.
     *
     * @param password the new password
     * @return a new JksSslStoreDetails instance
     */
    public JksSslStoreDetails withPassword(String password);

    /**
     * Factory method to create a new JksSslStoreDetails instance for the given location.
     *
     * @param location the location of the key store file
     * @return a new JksSslStoreDetails instance
     */
    public static JksSslStoreDetails forLocation(@Nullable String location);
}

JksSslStoreBundle

SslStoreBundle backed by Java KeyStore files.

package org.springframework.boot.ssl.jks;

import org.springframework.boot.ssl.SslStoreBundle;

/**
 * SslStoreBundle backed by a Java keystore.
 *
 * Supports standard JKS keystores as well as PKCS11 hardware keystores.
 *
 * Thread Safety: Thread-safe. Lazy-loads KeyStore instances on first access.
 *
 * @since 3.1.0
 */
public class JksSslStoreBundle implements SslStoreBundle {

    /**
     * Create a new JksSslStoreBundle instance.
     *
     * @param keyStoreDetails the key store details
     * @param trustStoreDetails the trust store details
     */
    public JksSslStoreBundle(@Nullable JksSslStoreDetails keyStoreDetails, @Nullable JksSslStoreDetails trustStoreDetails);

    /**
     * Create a new JksSslStoreBundle instance with custom resource loader.
     *
     * @param keyStoreDetails the key store details
     * @param trustStoreDetails the trust store details
     * @param resourceLoader the resource loader used to load content
     */
    public JksSslStoreBundle(@Nullable JksSslStoreDetails keyStoreDetails, @Nullable JksSslStoreDetails trustStoreDetails, ResourceLoader resourceLoader);

    @Override
    public @Nullable KeyStore getKeyStore();

    @Override
    public @Nullable String getKeyStorePassword();

    @Override
    public @Nullable KeyStore getTrustStore();
}

JKS Usage Example:

// Configure JKS-based SSL bundle
JksSslStoreDetails keyStore = new JksSslStoreDetails(
    "PKCS12",                           // type
    null,                               // provider
    "classpath:keystore.p12",          // location
    "changeit"                         // password
);

JksSslStoreDetails trustStore = new JksSslStoreDetails(
    "JKS",
    null,
    "classpath:truststore.jks",
    "changeit"
);

JksSslStoreBundle bundle = new JksSslStoreBundle(keyStore, trustStore);
KeyStore ks = bundle.getKeyStore();