【问题标题】:Client Certificate not working from Android - How to debug?客户端证书不适用于 Android - 如何调试?
【发布时间】:2014-06-29 13:41:27
【问题描述】:

我正在尝试为 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 没有用处)

谢谢!

【问题讨论】:

    标签: android ssl ssl-certificate bouncycastle spongycastle


    【解决方案1】:

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

    对于日志记录、调试,您可以创建自己的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-10-20
      • 2017-08-20
      • 2023-03-17
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      相关资源
      最近更新 更多