android自定义信任和密钥管理器

时间:2014-03-08 12:42:55

标签: java android sockets ssl certificate

我之前问过这个问题,但没有得到任何帮助。我已经取得了一些进展,但再次陷入了新的错误。

我必须使用一个安全的设备来保存密钥对和CA证书。当应用程序与需要相互身份验证的服务器建立TLS连接时,我现在必须使用此设备。我有一个“KeyPair”类,它能够与安全设备通信。

我的问题是,当建立ssl连接时,我在客户端上收到错误“tlsv1 alert unknown ca”,并在服务器上收到“SSL3_GET_CLIENT_CERTIFICATE:没有返回证书”。 我的调试日志显示SSL上下文确实将我的对象查询为信任管理器。首先调用checkServerTrusted()函数,然后传递。接下来调用chooseClientAlias()函数,然后调用带有客户端别名的getPrivateKey()函数。此时,我从设备中提取私钥并将其返回。接下来调用函数getCertificateChain(),然后在数组中获取并返回匹配的证书及其签名者CA.我的调试输出显示返回的证书为:

Subject DN: CN=be2576a357228b303189ab62bd2497807d2276493ddfc6fd037a0c8fc6e9ac9a,C=YY,E=a@b.com
Issuer DN: O=myCompany,E=email@mydomain.net,L=myCity,ST=myState,C=XX,CN=LJB
Serial Num = 3877882041

Subject DN = O=myCompany,E=email@mydomain.net,L=myCity,ST=myState,C=XX,CN=LJB
Issuer DN  = O=myCompany,E=email@mydomain.net,L=myCity,ST=myState,C=XX,CN=LJB
Serial Num = 10069430368951295741

SSL连接然后在失败之前暂停,并出现上述错误。

我已经扩展了“KeyPair”类,以充当这样的密钥和信任管理器:

public class Keypair implements X509KeyManager, X509TrustManager

在这个类中,我覆盖了这些管理器的所有函数,以查看何时调用。我的应用程序将永远是一个服务器的客户端。

因此,在创建此类对象期间,并且在设备上的密钥对的所有测试成功之后,我创建了一个使用特定密钥对的SSL上下文。目前,设备上只有一个密钥对。我用,......

sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(new KeyManager[] {this}, new TrustManager[] {this}, new SecureRandom());

稍后,任务将使用此对象创建与服务器的连接

protected boolean Connect(String host, int port) {
    SSLSocketFactory factory = getKeypair().getSecureSocketFactory();
    socket = (SSLSocket) factory.createSocket(host, port);
    :
}

其中getSecureSocketFactory()函数只是从keypair类对象返回sslCtx.getSocketFactory()。

我经常搜索并看到创建工厂等的代码,但没有人能够帮助我。我不想创建任何密钥库 - 这是设备的目的。

那么错误所指的“CA”是什么?服务器证书也由上述CA直接签名。如果我不要求客户端进行身份验证,则连接有效。我在使用Android 4.1.2的手机上进行测试。

跟进:我确定我的问题在于我的getCertificateChain()函数。我只是包含我从安全设备检索的公共证书和CA证书。它永远不应该使用Android附带的任何证书。那么,有人可以给我一些关于返回链条的规则的指示吗?我是否理解'链'是正确的:这必须是与私钥匹配的证书以及直到主CA的所有证书(自签名)?“

1 个答案:

答案 0 :(得分:0)

要设置您的TrustManager,我使用了一些我在某处找到的实用函数:

  void trustCertificate(X509Certificate cert) {
        if (cert!=null) {
            try {
                KeyStore.TrustedCertificateEntry x = new KeyStore.TrustedCertificateEntry(cert);
                sslKeystore.setEntry(cert.getSubjectDN().getName(), x, null);
            } catch (KeyStoreException e) {
                e.printStackTrace();
            }
            saveKeystore();
        }
    }

    private void createKeystore() {
        try {
            sslKeystore.load(null,null);
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init((KeyStore)null);
            // Copy current certs into our keystore so we can use it...
            // TODO: don't actually do this...
            X509TrustManager xtm = (X509TrustManager) tmf.getTrustManagers()[0];
            for (X509Certificate cert : xtm.getAcceptedIssuers()) {
                sslKeystore.setCertificateEntry(cert.getSubjectDN().getName(), cert);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        saveKeystore();
    }

    private void saveKeystore() {
        try {
            sslKeystore.store(new FileOutputStream(keystoreFile), KEYSTORE_PASSWORD.toCharArray());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

来自调用类:

 CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = new BufferedInputStream(cafile);
            Certificate ca = null;
            try {
                ca = cf.generateCertificate(caInput);

            } catch(Exception e) {

            }
            finally {
                caInput.close();
            }
            certManagerCA.trustCertificate((X509Certificate) ca);
            KeyStore keyStoreCA = certManagerCA.sslKeystore;
            tmf = TrustManagerFactory.getInstance("X509");
            tmf.init(keyStoreCA);