1

我正在尝试为 Android 应用程序实现客户端证书通信,但到目前为止没有取得多大成功 - 如果可能的话,这个功能似乎非常困难。我正在实施的完整流程在我之前的问题中进行了描述。

我按照那里的代码和这篇博文中的代码,或多或少地描述了相同的场景,但没有结果。

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

有什么作用:

  • 创建 PKCS#10 请求,将其发送到 CA 并获得签名的 PKCS#7 ( P7B )
  • 将收到的带有私钥的P7B存储在 KeyStore 中,并将其导出到 PKCS#12 ( P12 )
  • 最烦人的)从设备中挑选P12,将其安装在 Windows 上,联系服务器并获得一致的(200 HTTP-OK)响应。

我改变了什么:从我得到的代码示例(来自这里这里),我不得不改变一些事情。我正在使用 HttpsURLConnection 而不是 OkHttpClient 作为 @Than 在那里使用的(但这应该没关系),我不能像 Rich Freedman 那样提供证书(他证书,我通过 PKCS#10 和#7),所以我创建了一个信任服务器证书的 CustomTrustManager,因此我使用 SpongyCastle(v1.5.0.0 如果重要,设置为插入为 0 的提供程序)并且也不保留证书,但一切都在内存中完成。

问题是下一步该怎么做:

  • 我如何判断服务器的期望(客户端证书)?
  • 如何判断哪些客户端证书(如果有)正在发送到服务器?
  • 一般如何调试这种情况?(Fiddler 之类的代理对底层 SSL 没用)

谢谢!

4

1 回答 1

4

这不是一个好的答案,但这里有太多内容无法将其发布为评论。

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

@DebugLog注释来自 Jake Wharton 创建的 Hugo 库。它打印函数参数及其返回的内容。你可以使用普通的 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);

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

于 2014-06-29T16:09:54.567 回答