问题
I have in my hand an SSL LDAP server certificate. I want to use it to connect to the LDAP server using UnboundID SDK.
I do not want to use com.unboundid.util.ssl.TrustAllTrustManager as was showed here: Using UnboundID SDK with an SSL certificate file to connect to LDAP server in Android app
The following TrustManagers not fit our product requirements:
com.unboundid.util.ssl.PromptTrustManager
com.unboundid.util.ssl.HostNameTrustManager
com.unboundid.util.ssl.ValidityDateTrustManager
I do not want any user interaction, and what I miss in the list above the TrustManager that validate the certificate issuers.
Also, I do not want to insert the LDAP server certificate in any keystore, so I can not use the following TrustManagers:
com.unboundid.util.ssl.WrapperKeyManager
com.unboundid.util.ssl.PKCS11KeyManager
com.unboundid.util.ssl.KeyStoreKeyManager
I want to do something like the code below:
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(byteArrayInputStream);
SSLUtil sslUtil = new SSLUtil(new CertificateTrustManager(cert));
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory,
"server.example.com", 636);
Please note, that CertificateTrustManager does not exist in UnboundID SDK. How is possible to do it?
回答1:
I found the solution using Using UnboundID SDK with an SSL certificate file to connect to LDAP server in Android app and How to import a .cer certificate into a java keystore? (answer of Patrick M).
Now I can take a certificate from UI and connect to LDAP via SSL :)
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.util.ssl.SSLUtil;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
String base64EncodedCertificateString = "...";
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(base64EncodedCertificateString.getBytes());
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
int i = 0;
while (byteArrayInputStream.available() > 0) {
Certificate cert = cf.generateCertificate(byteArrayInputStream);
trustStore.setCertificateEntry("cert " + i++, cert);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLUtil sslUtil = new SSLUtil(trustManagers);
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory);
connection.connect("place.myserver.com", 636);
回答2:
If there is a specific certificate or set of certificates that you want trusted, then you could just create your own custom javax.net.ssl.X509TrustManager implementations that examines the presented certificate chain and determines whether it represents one of the expected certificates. You could hard-code information about those certificates into your code (or better yet, put it in a config file so you could change it without altering any code) and do something like comparing certificate fingerprints to get an appropriate degree of assurance that it is actually the legitimate certificate.
If you don't know what the individual certificates will be but know that they all have a common issuer, and you trust that issuer to only issue good certificates, then you could include trust information for that issuer.
If you want to allow for a range of unknown certificates, potentially from untrusted issuers (and you don't know what those issuers might be in advance), and you don't want to prompt the user about whether to trust them (which you could potentially cache so you only have to ask once), then I'm not sure what you could do. Unless you can find some way to differentiate certificates from good servers versus those from bad servers, then your application will run the risk of either trusting bad certificates or not trusting good ones.
回答3:
Though it is not recommended for security reasons, it can sometimes be useful at least for testing situations to use the TrustAllTrustManager as follows:
TrustAllTrustManager tm = new TrustAllTrustManager();
TrustManager[] trustManagers = new TrustManager[] {tm};
SSLUtil sslUtil = new SSLUtil(trustManagers);
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory);
This is NOT supposed to be used for production environments!
来源:https://stackoverflow.com/questions/17656392/how-to-use-unboundid-sdk-to-connect-to-an-ldap-server-with-the-ssl-server-certif