6

我手里有一个 SSL LDAP 服务器证书。我想用它来使用 UnboundID SDK 连接到 LDAP 服务器。

我不想使用 com.unboundid.util.ssl.TrustAllTrustManager 如下所示: Using UnboundID SDK with an SSL certificate file to connect to LDAP server in Android app

以下 TrustManager 不符合我们的产品要求:

com.unboundid.util.ssl.PromptTrustManager
com.unboundid.util.ssl.HostNameTrustManager
com.unboundid.util.ssl.ValidityDateTrustManager

我不想要任何用户交互,以及我在 TrustManager 上方验证证书颁发者的列表中遗漏的内容。

另外,我不想在任何密钥库中插入 LDAP 服务器证书,所以我不能使用以下 TrustManager:

com.unboundid.util.ssl.WrapperKeyManager
com.unboundid.util.ssl.PKCS11KeyManager
com.unboundid.util.ssl.KeyStoreKeyManager

我想做类似下面的代码:

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);

请注意,UnboundID SDK 中不存在 CertificateTrustManager。怎么可能做到呢?

4

3 回答 3

7

我找到了使用 UnboundID SDK 和 SSL 证书文件连接到 Android 应用程序中的 LDAP 服务器以及如何将 .cer 证书导入 java 密钥库的解决方案?(帕特里克 M 的回答)。

现在我可以从 UI 获取证书并通过 SSL 连接到 LDAP :)

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);
于 2013-07-16T12:25:54.733 回答
3

如果存在您希望信任的特定证书或一组证书,那么您可以创建自己的自定义 javax.net.ssl.X509TrustManager 实现来检查提供的证书链并确定它是否代表预期的证书之一。您可以将有关这些证书的信息硬编码到您的代码中(或者更好的是,将其放在一个配置文件中,这样您就可以在不更改任何代码的情况下更改它)并执行诸如比较证书指纹之类的操作,以获得适当程度的保证。实际上是合法的证书。

如果您不知道各个证书将是什么,但知道它们都有一个共同的颁发者,并且您相信该颁发者只会颁发良好的证书,那么您可以包含该颁发者的信任信息。

如果您想允许一系列未知证书,可能来自不受信任的颁发者(并且您事先不知道这些颁发者可能是什么),并且您不想提示用户是否信任它们(您可能会缓存,所以你只需要问一次),那么我不确定你能做什么。除非您能找到某种方法来区分证书与好服务器和坏服务器,否则您的应用程序将面临信任坏证书或不信任好证书的风险。

于 2013-07-15T16:01:08.807 回答
0

尽管出于安全原因不建议这样做,但有时至少在测试情况下使用 TrustAllTrustManager 很有用,如下所示:

TrustAllTrustManager tm = new TrustAllTrustManager();
TrustManager[] trustManagers = new TrustManager[] {tm};
SSLUtil sslUtil = new SSLUtil(trustManagers);
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory);

这不应该用于生产环境!

于 2015-02-18T23:20:02.797 回答