Class SSLUtil

java.lang.Object
com.unboundid.util.ssl.SSLUtil

This class provides a relatively simple interface for helping to configure secure communication using TLS (formerly known as SSL) and StartTLS (which uses an LDAP extended operation to convert an already-established non-secure connection to one that uses TLS security). When establishing secure connections, there are five main concepts to be aware of:
  • The allowed set of TLS protocol versions
  • The allowed set of TLS cipher suites
  • The key manager (if any) to use for obtaining local certificates
  • The trust manager to use for determining whether to trust peer certificates
  • The logic used to validate certificate hostnames
Each of these is covered in more detail below.

TLS Protocol Versions

The TLS protocol has evolved over time to improve both security and efficiency, and each update to the protocol has been assigned a version number. At present, only TLSv1.3 and TLSv1.2 are considered secure, and only those versions will be enabled by default, with TLSv1.3 preferred over TLSv1.2. Note that some older JVMs do not support TLSv1.3, and only TLSv1.2 will be enabled by default in that case. In the very unlikely event that the JVM does not support either TLSv1.3 or TLSv1.2, the LDAP SDK may fall back to enabling support for TLSv1.1 or TLSv1.

If you want or need to explicitly specify the TLS protocol versions to use for secure communication, then you may use the setEnabledSSLProtocols(java.util.Collection<java.lang.String>) method to indicate which protocol versions are allowed, and the setDefaultSSLProtocol(java.lang.String) method to indicate which is the preferred protocol version. You can use any TLS protocol version that the underlying JVM supports.

It is also possible to specify the set of enabled and default TLS protocol versions using Java system properties. The com.unboundid.util.SSLUtil.enabledSSLProtocols property may be set with a comma-delimited list of the TLS protocol versions that should be enabled by default, and the com.unboundid.util.SSLUtil.defaultSSLProtocol property may be set with the protocol version that should be preferred. If set, these properties will override the logic that the LDAP SDK automatically uses to select default values, but those defaults may be explicitly overridden by calls to the setEnabledSSLProtocols and setDefaultSSLProtocol methods.

TLS Cipher Suites

A cipher suite encapsulates a number of settings that will be used to actually secure TLS communication between two systems, including which algorithm to use for key exchange, which algorithm to use for bulk encryption, and which algorithm to use for integrity protection. The JVM supports a fixed set of TLS cipher suites, although it may only enable support for a subset of those by default, and the LDAP SDK may further disable support for some of those suites by default for security reasons. The logic that the LDAP SDK uses to select a good default set of TLS cipher suites is encapsulated in the TLSCipherSuiteSelector class, and the class-level documentation for that class describes the criteria that it uses to make its selection.

If you wish to override the LDAP SDK's default selection, you may use the setEnabledSSLCipherSuites(java.util.Collection<java.lang.String>) method to explicitly specify the set of cipher suites that should be enabled. Alternatively, the com.unboundid.util.SSLUtil.enabledSSLCipherSuites system property may be set with a comma-delimited list of the cipher suites that should be enabled.

Key Managers

A key manager is used to obtain access to a certificate chain and private key that should be presented to the peer during TLS negotiation. In the most common use cases, in which the LDAP SDK is used only to establish outbound connections and does not need to use a certificate to authenticate itself to the LDAP server, there won't be any need to present a certificate chain, and there won't be any need to configure a key manager. However, if you are using the LDAP SDK to accept TLS-secured connections from LDAP clients (for example, using the InMemoryDirectoryServer or another type of LDAPListener), if the server requires clients to present their own certificate for mutual TLS authentication, or if you want to use the SASL EXTERNAL mechanism to use a client certificate to authenticate to the server at the LDAP layer, then you will need to specify a key manager to provide access to that certificate chain. The key manager to use for that purpose should be provided in the SSLUtil constructor.

While any javax.net.ssl.KeyManager instance can be used, the LDAP SDK provides three options that will be sufficient for most use cases:
  • KeyStoreKeyManager -- Allows the certificate chain and private key to be obtained from a key store file, which will typically be in the JKS or PKCS #12 format (or in the Bouncy Castle BCFKS format when using the LDAP SDK in FIPS-compliant mode).
  • PEMFileKeyManager -- Allows the certificate chain and private key to be obtained from text files that contain the PEM-encoded representation of X.509 certificates and a PKCS #8 private key.
  • PKCS11KeyManager -- Allows the certificate chain and private key to be accessed from a PKCS #11 token, like a hardware security module (HSM).


Trust Managers

A trust manager is used to determine whether to trust a certificate chain presented by a peer during TLS negotiation. Trust is a very important aspect of TLS because it's important to make sure that the peer you're communicating with is actually who you intend it to be and not someone else who has managed to hijack the negotiation process.

You will generally always want to provide a trust manager, regardless of whether you're using the LDAP SDK to act as a client or a server, and this trust manager should be provided in the SSLUtil constructor. The LDAP SDK offers several trust manager implementations, including:
  • JVMDefaultTrustManager -- Uses the JVM's default cacerts trust store to obtain access to a set of trusted, well-known issuer certificates, including those from commercial certification authorities like Verisign or DigiCert, and from trusted free providers like Let's Encrypt. This trust manager will only accept valid certificates that have been signed by one of those trusted authorities.
  • TrustStoreTrustManager -- Uses the information in a trust store file (typically in a format like JKS, PKCS #12 or BCFKS) as a set of trusted certificates and issuers.
  • PEMFileTrustManager -- Uses the information one or more files containing the PEM representations of X.509 certificates as a set of trusted certificates and issuers.
  • TopologyRegistryTrustManager -- Uses the topology registry information in the configuration of a Ping Identity Directory Server (or related server product) to obtain a set of trusted certificates and issuers.
  • PromptTrustManager -- Interactively prompts the user (via the terminal) to determine whether the presented certificate chain should be trusted.
  • TrustAllTrustManager -- Blindly trusts all certificate chains that are presented to it. This may be convenient in some cases for testing purposes, but it is strongly discouraged for production use because it does not actually perform any real trust processing and will allow connecting to unintended or malicious peers.
  • AggregateTrustManager -- Allows you to combine multiple other trust managers in the course of determining whether to trust a presented certificate chain. For example, you may use this to automatically trust certificates signed by an issuer in the JVM's cacerts file or in an explicitly specified alternative trust store file, but to fall back to interactively prompting the user for certificates not trusted by one of the previous two methods.


Certificate Hostname Validation

Trust managers can be used to ensure that a certificate chain presented by a peer originally came from a trusted source, but that doesn't necessarily mean that the peer system is the one you intend it to be. It's not at all difficult for malicious users and applications to obtain a certificate that is signed by a CA in the JVM's default set of trusted issuers. However, any certificate signed by one of those trusted issuers will include information in a subject alternative name extension that specifies the hostnames (or at least domain names) and IP addresses for systems with which that certificate is allowed to be used, and those issues are careful to verify that they only issue certificates to systems that are legitimately associated with those systems. So while a malicious user may be able to easily get a certificate from a trusted issuer, it should not be possible for them to get a certificate with a subject alternative name extension containing addresses they don't legitimately have the right to use.

Because of this, it's very important that clients not only verify that the server's certificate comes from a trusted source, but also that it's allowed to be used by that server system. This additional level of validation can help thwart attacks that rely on DNS hijacking or other methods of diverting communication away from the intended recipient to one that an attacker controls instead. The LDAP SDK does not perform this validation by default because there are unfortunately too many cases in which clients (especially those used in testing and development environments) might need to interact with a server whose certificate may not have an appropriate subject alternative name extension. However, in production environments with a properly configured TLS certificate, hostname verification can be enabled by calling the LDAPConnectionOptions.setSSLSocketVerifier(com.unboundid.util.ssl.SSLSocketVerifier) method with an instance of the HostNameSSLSocketVerifier. Alternatively, you can set the com.unboundid.ldap.sdk. LDAPConnectionOptions.defaultVerifyCertificateHostnames system property with a value of "true" to enable this validation by default.

Examples

The following example demonstrates the process for establish a secure client connection. It relies on the LDAP SDK's default configuration for selecting TLS protocols and cipher suites, and does not use a key manager. It uses an aggregate trust manager to automatically trust any certificates signed by one of the JVM's default trusted issuers or an issuer in an explicitly specified key store file, and it enables host name validation.

   AggregateTrustManager trustManager = new AggregateTrustManager(false,
        JVMDefaultTrustManager.getInstance(),
        new TrustStoreTrustManager(trustStorePath, trustStorePIN,
             "PKCS12", true));
   SSLUtil sslUtil = new SSLUtil(trustManager);

   LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
   connectionOptions.setSSLSocketVerifier(
        new HostNameSSLSocketVerifier(true));

   try (LDAPConnection connection = new LDAPConnection(
             sslUtil.createSSLSocketFactory(), connectionOptions,
             serverAddress, serverLDAPSPort))
   {
     // Use the connection here.
     RootDSE rootDSE = connection.getRootDSE();
   }
 


The above example establishes an LDAPS connection that is secured by TLS as soon as it is created. The following example shows the process needed to use the StartTLS extended operation to secure an already-established non-secure connection:

   AggregateTrustManager trustManager = new AggregateTrustManager(false,
        JVMDefaultTrustManager.getInstance(),
        new TrustStoreTrustManager(trustStorePath, trustStorePIN,
             "PKCS12", true));
   SSLUtil sslUtil = new SSLUtil(trustManager);

   LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
   connectionOptions.setSSLSocketVerifier(
        new HostNameSSLSocketVerifier(true));

   try (LDAPConnection connection = new LDAPConnection(
             connectionOptions, serverAddress, serverLDAPPort))
   {
     // Use the StartTLS extended operation to secure the connection.
     ExtendedResult startTLSResult;
     try
     {
       startTLSResult = connection.processExtendedOperation(
            new StartTLSExtendedRequest(
                 sslUtil.createSSLSocketFactory()));
     }
     catch (LDAPException e)
     {
       Debug.debugException(e);
       startTLSResult = new ExtendedResult(e);
     }
     LDAPTestUtils.assertResultCodeEquals(startTLSResult,
          ResultCode.SUCCESS);

     // Use the connection here.
     RootDSE rootDSE = connection.getRootDSE();
   }
 
  • Field Details

  • Constructor Details

    • SSLUtil

      public SSLUtil()
      Creates a new SSLUtil instance that will not have a custom key manager or trust manager. It will not be able to provide a certificate to the server if one is requested, and it will only trust certificates signed by a predefined set of authorities.
    • SSLUtil

      public SSLUtil(@Nullable TrustManager trustManager)
      Creates a new SSLUtil instance that will use the provided trust manager to determine whether to trust server certificates presented to the client. It will not be able to provide a certificate to the server if one is requested.
      Parameters:
      trustManager - The trust manager to use to determine whether to trust server certificates presented to the client. It may be null if the default set of trust managers should be used.
    • SSLUtil

      public SSLUtil(@Nullable TrustManager[] trustManagers)
      Creates a new SSLUtil instance that will use the provided trust managers to determine whether to trust server certificates presented to the client. It will not be able to provide a certificate to the server if one is requested.
      Parameters:
      trustManagers - The set of trust managers to use to determine whether to trust server certificates presented to the client. It may be null or empty if the default set of trust managers should be used.
    • SSLUtil

      public SSLUtil(@Nullable KeyManager keyManager, @Nullable TrustManager trustManager)
      Creates a new SSLUtil instance that will use the provided key manager to obtain certificates to present to the server, and the provided trust manager to determine whether to trust server certificates presented to the client.
      Parameters:
      keyManager - The key manager to use to obtain certificates to present to the server if requested. It may be null if no client certificates will be required or should be provided.
      trustManager - The trust manager to use to determine whether to trust server certificates presented to the client. It may be null if the default set of trust managers should be used.
    • SSLUtil

      public SSLUtil(@Nullable KeyManager[] keyManagers, @Nullable TrustManager[] trustManagers)
      Creates a new SSLUtil instance that will use the provided key managers to obtain certificates to present to the server, and the provided trust managers to determine whether to trust server certificates presented to the client.
      Parameters:
      keyManagers - The set of key managers to use to obtain certificates to present to the server if requested. It may be null or empty if no client certificates will be required or should be provided.
      trustManagers - The set of trust managers to use to determine whether to trust server certificates presented to the client. It may be null or empty if the default set of trust managers should be used.
  • Method Details

    • getKeyManagers

      Retrieves the set of key managers configured for use by this class, if any.
      Returns:
      The set of key managers configured for use by this class, or null if none were provided.
    • getTrustManagers

      Retrieves the set of trust managers configured for use by this class, if any.
      Returns:
      The set of trust managers configured for use by this class, or null if none were provided.
    • createSSLContext

      Creates an initialized SSL context created with the configured key and trust managers. It will use the protocol returned by the getDefaultSSLProtocol() method and the JVM-default provider.
      Returns:
      The created SSL context.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL context.
    • createSSLContext

      Creates an initialized SSL context created with the configured key and trust managers. It will use a default provider.
      Parameters:
      protocol - The SSL protocol to use. The Java Secure Socket Extension (JSSE) Reference Guide provides a list of the supported protocols, but commonly used values are "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1". This must not be null.
      Returns:
      The created SSL context.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL context.
    • createSSLContext

      Creates an initialized SSL context created with the configured key and trust managers.
      Parameters:
      protocol - The SSL protocol to use. The Java Secure Socket Extension (JSSE) Reference Guide provides a list of the supported protocols, but commonly used values are "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1". This must not be null.
      provider - The name of the provider to use for cryptographic operations. It must not be null.
      Returns:
      The created SSL context.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL context.
    • createSSLSocketFactory

      Creates an SSL socket factory using the configured key and trust manager providers. It will use the protocol returned by the getDefaultSSLProtocol() method and the JVM-default provider.
      Returns:
      The created SSL socket factory.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL socket factory.
    • createSSLSocketFactory

      Creates an SSL socket factory with the configured key and trust managers. It will use the default provider.
      Parameters:
      protocol - The SSL protocol to use. The Java Secure Socket Extension (JSSE) Reference Guide provides a list of the supported protocols, but commonly used values are "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1". This must not be null.
      Returns:
      The created SSL socket factory.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL socket factory.
    • createSSLSocketFactory

      Creates an SSL socket factory with the configured key and trust managers.
      Parameters:
      protocol - The SSL protocol to use. The Java Secure Socket Extension (JSSE) Reference Guide provides a list of the supported protocols, but commonly used values are "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1". This must not be null.
      provider - The name of the provider to use for cryptographic operations. It must not be null.
      Returns:
      The created SSL socket factory.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL socket factory.
    • createSSLServerSocketFactory

      Creates an SSL server socket factory using the configured key and trust manager providers. It will use the protocol returned by the getDefaultSSLProtocol() method and the JVM-default provider.
      Returns:
      The created SSL server socket factory.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL server socket factory.
    • createSSLServerSocketFactory

      Creates an SSL server socket factory using the configured key and trust manager providers. It will use the JVM-default provider.
      Parameters:
      protocol - The SSL protocol to use. The Java Secure Socket Extension (JSSE) Reference Guide provides a list of the supported protocols, but commonly used values are "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1". This must not be null.
      Returns:
      The created SSL server socket factory.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL server socket factory.
    • createSSLServerSocketFactory

      Creates an SSL server socket factory using the configured key and trust manager providers.
      Parameters:
      protocol - The SSL protocol to use. The Java Secure Socket Extension (JSSE) Reference Guide provides a list of the supported protocols, but commonly used values are "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1". This must not be null.
      provider - The name of the provider to use for cryptographic operations. It must not be null.
      Returns:
      The created SSL server socket factory.
      Throws:
      GeneralSecurityException - If a problem occurs while creating or initializing the SSL server socket factory.
    • getDefaultSSLProtocol

      Retrieves the SSL protocol string that will be used by calls to createSSLContext() that do not explicitly specify which protocol to use.
      Returns:
      The SSL protocol string that will be used by calls to create an SSL context that do not explicitly specify which protocol to use.
    • setDefaultSSLProtocol

      public static void setDefaultSSLProtocol(@NotNull String defaultSSLProtocol)
      Specifies the SSL protocol string that will be used by calls to createSSLContext() that do not explicitly specify which protocol to use.
      Parameters:
      defaultSSLProtocol - The SSL protocol string that will be used by calls to create an SSL context that do not explicitly specify which protocol to use. It must not be null.
    • getEnabledSSLProtocols

      Retrieves the set of SSL protocols that will be enabled for use, if available, for SSL sockets created within the LDAP SDK.
      Returns:
      The set of SSL protocols that will be enabled for use, if available, for SSL sockets created within the LDAP SDK.
    • setEnabledSSLProtocols

      public static void setEnabledSSLProtocols(@Nullable Collection<String> enabledSSLProtocols)
      Specifies the set of SSL protocols that will be enabled for use for SSL sockets created within the LDAP SDK. When creating an SSL socket, the SSLSocket.getSupportedProtocols method will be used to determine which protocols are supported for that socket, and then the SSLSocket.setEnabledProtocols method will be used to enable those protocols which are listed as both supported by the socket and included in this set. If the provided set is null or empty, then the default set of enabled protocols will be used.
      Parameters:
      enabledSSLProtocols - The set of SSL protocols that will be enabled for use for SSL sockets created within the LDAP SDK. It may be null or empty to indicate that the JDK-default set of enabled protocols should be used for the socket.
    • applyEnabledSSLProtocols

      public static void applyEnabledSSLProtocols(@NotNull Socket socket) throws LDAPException
      Updates the provided socket to apply the appropriate set of enabled SSL protocols. This will only have any effect for sockets that are instances of javax.net.ssl.SSLSocket, but it is safe to call for any kind of java.net.Socket. This should be called before attempting any communication over the socket.
      Parameters:
      socket - The socket on which to apply the configured set of enabled SSL protocols.
      Throws:
      LDAPException - If getEnabledSSLProtocols() returns a non-empty set but none of the values in that set are supported by the socket.
    • getEnabledSSLCipherSuites

      Retrieves the set of SSL cipher suites that will be enabled for use, if available, for SSL sockets created within the LDAP SDK.
      Returns:
      The set of SSL cipher suites that will be enabled for use, if available, for SSL sockets created within the LDAP SDK.
    • setEnabledSSLCipherSuites

      public static void setEnabledSSLCipherSuites(@Nullable Collection<String> enabledSSLCipherSuites)
      Specifies the set of SSL cipher suites that will be enabled for SSL sockets created within the LDAP SDK. When creating an SSL socket, the SSLSocket.getSupportedCipherSuites method will be used to determine which cipher suites are supported for that socket, and then the SSLSocket.setEnabledCipherSuites method will be used to enable those suites which are listed as both supported by the socket and included in this set. If the provided set is null or empty, then the default set of enabled cipher suites will be used.
      Parameters:
      enabledSSLCipherSuites - The set of SSL cipher suites that will be enabled for use for SSL sockets created within the LDAP SDK. It may be null or empty to indicate that the JDK-default set of enabled cipher suites should be used for the socket.
    • applyEnabledSSLCipherSuites

      public static void applyEnabledSSLCipherSuites(@NotNull Socket socket) throws LDAPException
      Updates the provided socket to apply the appropriate set of enabled SSL cipher suites. This will only have any effect for sockets that are instances of javax.net.ssl.SSLSocket, but it is safe to call for any kind of java.net.Socket. This should be called before attempting any communication over the socket.
      Parameters:
      socket - The socket on which to apply the configured set of enabled SSL cipher suites.
      Throws:
      LDAPException - If getEnabledSSLCipherSuites() returns a non-empty set but none of the values in that set are supported by the socket.
    • certificateToString

      Creates a string representation of the provided certificate.
      Parameters:
      certificate - The certificate for which to generate the string representation. It must not be null.
      Returns:
      A string representation of the provided certificate.
    • certificateToString

      public static void certificateToString(@NotNull X509Certificate certificate, @NotNull StringBuilder buffer)
      Appends a string representation of the provided certificate to the given buffer.
      Parameters:
      certificate - The certificate for which to generate the string representation. It must not be null.
      buffer - The buffer to which to append the string representation.