客户端证书无法在Android上运行 - 如何调试?

时间:2014-06-29 13:41:27

标签: android ssl ssl-certificate bouncycastle spongycastle

我试图为Android应用程序实现客户端证书通信,到目前为止没有太大的成功 - 而且似乎这个功能,如果可能的话,非常难。我实施的完整流程在my previous question中有所描述。

我按照那里的代码和来自this blog post的代码,描述相同的场景,或多或少,没有结果。

什么行不通:在Android客户端和服务器之间打开SSL连接(HttpsURLConnection)会导致服务器返回403 status code
AFAIK,这403是因为服务器没有或不信任它获得的客户端证书,我不知道如何调试它。

有什么作用:

  • 创建PKCS#10请求,将其发送到CA并获取已签名的PKCS#7( P7B
  • 使用私钥将收到的 P7B 存储在KeyStore中,并将其导出到PKCS#12( P12
  • 最为繁荣)从设备中选择 P12 ,将其安装在Windows上,与服务器联系并获得连贯的(200 HTTP-OK)响应。

我改变了什么:从我得到的代码示例(来自herehere),我不得不改变一些事情。我使用HttpsURLConnection而不是OkHttpClient作为@Than在那里使用(但它不重要),我不能像Rich Freedman那样提供证书(他已经证书,我通过PKCS#10和#7获得它,所以我创建了一个信任服务器证书的CustomTrustManager,因此我使用SpongyCastle(v1.5.0) .0如果重要,设置为0)插入的提供者,也不要持久保存证书,但所有内容都在内存中完成。

问题下一步该做什么:

  • 如何判断服务器的期望(客户端证书明智)?
  • 如何判断哪些客户端证书(如果有)被发送到服务器?
  • 如何调试此方案一般? (像Fiddler这样的代理对于底层SSL来说是无用的)

谢谢!

1 个答案:

答案 0 :(得分:4)

这不是一个好的答案,但是这里有太多的东西要发表评论。

对于日志记录,调试,您可以创建自己的X509KeyManager,它使用从KeyManagerFactory获得的普通密钥管理器:

@DebugLog注释来自杰克沃顿创建的雨果图书馆。它打印函数参数及其返回的内容。您可以使用普通的Log.d或任何您想要的。

例如:

class MyKeyManager implements X509KeyManager {

    private final X509KeyManager keyManager;

    MyKeyManager(X509KeyManager keyManager) {
        this.keyManager = keyManager;
    }

    @DebugLog
    @Override
    public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
        return this.keyManager.chooseClientAlias(strings, principals, socket);
    }

    @DebugLog
    @Override
    public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
        return keyManager.chooseServerAlias(s, principals, socket);
    }

    @DebugLog
    @Override
    public X509Certificate[] getCertificateChain(String s) {
        return keyManager.getCertificateChain(s);
    }

    @DebugLog
    @Override
    public String[] getClientAliases(String s, Principal[] principals) {
        return keyManager.getClientAliases(s, principals);
    }

    @DebugLog
    @Override
    public String[] getServerAliases(String s, Principal[] principals) {
        return keyManager.getServerAliases(s, principals);
    }

    @DebugLog
    @Override
    public PrivateKey getPrivateKey(String s) {
        return keyManager.getPrivateKey(s);
    }
}

并使用它来初始化SSLContext

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password);

final X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
X509KeyManager km = new MyKeyManager(origKm);

SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(new KeyManager[]{km}, tmf.getTrustManagers(), null);

您将看到调用哪个方法,参数是什么(从服务器证书获得)以及您的keymanager返回的证书和私钥。