diff --git a/docs/release-notes.html b/docs/release-notes.html
index bc63543cd..60b6b4889 100644
--- a/docs/release-notes.html
+++ b/docs/release-notes.html
@@ -56,6 +56,15 @@
Version 4.0.13
+
+ Updated the manage-certificates check-certificate-usability command to add an
+ additional check to see whether the certificate at the root of the chain is
+ found in the JVM's set of trusted issuer certificates. If the CA certificate
+ is not found in the JVM's default trust store, a notice will be displayed, but
+ the tool will still complete with a success result.
+
+
+
Made the ManageCertificates.readCertificatesFromFile method public so
that it can be used outside of the LDAP SDK. This method can be used to read a
diff --git a/messages/unboundid-ldapsdk-cert.properties b/messages/unboundid-ldapsdk-cert.properties
index 8dc7f26bd..17d08da1e 100644
--- a/messages/unboundid-ldapsdk-cert.properties
+++ b/messages/unboundid-ldapsdk-cert.properties
@@ -2086,6 +2086,16 @@ ERR_MANAGE_CERTS_CHECK_USABILITY_CHAIN_ISSUER_MISMATCH=ERROR: The \
INFO_MANAGE_CERTS_CHECK_USABILITY_CHAIN_COMPLETE=OK: The certificate chain \
is complete. Each subsequent certificate is the issuer for the previous \
certificate in the chain, and the chain ends with a self-signed certificate.
+INFO_MANAGE_CERTS_CHECK_USABILITY_CA_TRUSTED_OK=OK: CA certificate ''{0}'' \
+ was found in the JVM's default set of trusted certificates. Most clients \
+ will likely trust this issuer.
+NOTE_MANAGE_CERTS_CHECK_USABILITY_CA_NOT_IN_JVM_DEFAULT_TS=NOTICE: CA \
+ certificate ''{0}'' was not found in the JVM's default set of trusted \
+ certificates. Clients will likely need special configuration to trust this \
+ certificate chain.
+WARN_MANAGE_CERTS_CHECK_USABILITY_CHECK_CA_IN_TS_ERROR=WARNING: An error \
+ occurred while attempting to determine whether CA certificate ''{0}'' is \
+ contained in the JVM-default trust store: {1}
INFO_MANAGE_CERTS_CHECK_USABILITY_CERT_SIGNATURE_VALID=OK: Certificate \
''{0}'' has a valid signature.
ERR_MANAGE_CERTS_CHECK_USABILITY_END_CERT_NOT_YET_VALID=ERROR: Certificate \
diff --git a/src/com/unboundid/util/ssl/cert/ManageCertificates.java b/src/com/unboundid/util/ssl/cert/ManageCertificates.java
index 9e841b09b..3968a387a 100644
--- a/src/com/unboundid/util/ssl/cert/ManageCertificates.java
+++ b/src/com/unboundid/util/ssl/cert/ManageCertificates.java
@@ -8294,6 +8294,73 @@ else if ((chain.length == 1) || (! chain[chain.length - 1].isSelfSigned()))
}
+ // If there are multiple certificates in the chain, and if the last
+ // certificate in the chain is self-signed, then check to see if it is
+ // contained in the JVM-default trust manager. If it isn't, then we'll
+ // display a notice, but we won't consider it a warning in and of itself.
+ if ((chain.length > 1) && chain[chain.length-1].isSelfSigned())
+ {
+ final X509Certificate caCert = chain[chain.length-1];
+
+ try
+ {
+ final String jvmDefaultTrustStoreType =
+ inferKeystoreType(JVM_DEFAULT_CACERTS_FILE);
+ final KeyStore jvmDefaultTrustStore =
+ KeyStore.getInstance(jvmDefaultTrustStoreType);
+ try (FileInputStream inputStream =
+ new FileInputStream(JVM_DEFAULT_CACERTS_FILE))
+ {
+ jvmDefaultTrustStore.load(inputStream, null);
+ }
+
+ boolean found = false;
+ final Enumeration aliases = jvmDefaultTrustStore.aliases();
+ while (aliases.hasMoreElements())
+ {
+ final String jvmDefaultCertAlias = aliases.nextElement();
+ if (jvmDefaultTrustStore.isCertificateEntry(jvmDefaultCertAlias))
+ {
+ final Certificate c =
+ jvmDefaultTrustStore.getCertificate(jvmDefaultCertAlias);
+ final X509Certificate xc = new X509Certificate(c.getEncoded());
+ if ((caCert.getSubjectDN().equals(xc.getSubjectDN())) &&
+ Arrays.equals(caCert.getSignatureValue().getBits(),
+ xc.getSignatureValue().getBits()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found)
+ {
+ out();
+ wrapOut(0, WRAP_COLUMN,
+ INFO_MANAGE_CERTS_CHECK_USABILITY_CA_TRUSTED_OK.get(
+ caCert.getSubjectDN()));
+ }
+ else
+ {
+ out();
+ wrapOut(0, WRAP_COLUMN,
+ NOTE_MANAGE_CERTS_CHECK_USABILITY_CA_NOT_IN_JVM_DEFAULT_TS.get(
+ caCert.getSubjectDN()));
+ }
+ }
+ catch (final Exception e)
+ {
+ Debug.debugException(e);
+ err();
+ wrapErr(0, WRAP_COLUMN,
+ WARN_MANAGE_CERTS_CHECK_USABILITY_CHECK_CA_IN_TS_ERROR.get(
+ caCert.getSubjectDN(), StaticUtils.getExceptionMessage(e)));
+ numWarnings++;
+ }
+ }
+
+
// Make sure that the signature is valid for each certificate in the
// chain. If any certificate has an invalid signature, then that's an
// error.