【问题标题】:Self-signed certificate verification not throwing SignatureException in Android自签名证书验证不会在 Android 中抛出 SignatureException
【发布时间】:2015-10-28 20:33:34
【问题描述】:

在下面的 Android 应用代码中,服务器向连接的 Android 客户端提供了一个自签名证书。也就是说,我已经用我自己的 CA 签署了服务器的证书。该证书将使用 CA 的公钥进行验证,该公钥是从位于 /raw 中的名为 trust_store_ca 的文件中获得的。问题是,如果我使用不同的证书(即使用不同的 CA 签名),验证步骤不会引发相应的 SignatureException。我已经在 NetBeans 中测试了代码,确实抛出了上述异常。然而,在 AndroidStudio 它没有。可能是什么问题?

KeyStore ts = KeyStore.getInstance("BKS");
InputStream trustin = v.getResources().openRawResource(R.raw.trust_store_ca);
ts.load(trustin, "MyKey".toCharArray());
// Create own trustmanager with self-signed cert.
final TrustManagerFactory tmf = TrustManagerFactory.
    getInstance(KeyManagerFactory.getDefaultAlgorithm());
//tmf.init((KeyStore) null);
tmf.init(ts);
trustManagers = tmf.getTrustManagers();

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream cA_certificate = v.getResources().openRawResource(R.raw.ca_certif);
final X509Certificate caCertificate = (X509Certificate)cf
    .generateCertificate(cA_certificate);
// Check server certificate is valid
final X509TrustManager origTrustmanager = (X509TrustManager)trustManagers[0];

wrappedTrustManagers = new TrustManager[]{
                                    new X509TrustManager() {
    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                            return origTrustmanager.getAcceptedIssuers();
                                        }
    @Override
    public void checkClientTrusted(X509Certificate[] certs, String authType) {//Not used}

    @Override
    public void checkServerTrusted(X509Certificate[] certs, String authType) 
throws CertificateException{
    if (certs == null || certs.length == 0) {
        throw new IllegalArgumentException(
"checkServerTrusted: null or zero-length certificate chain");
    }
    if (authType == null || authType.length() == 0) {
        throw new IllegalArgumentException(
"checkServerTrusted: null or zero-length authentication type");
    }

// This does not work in Android, at least from me in JB...
//
// try { 
//      certs[0].verify(caCertificate.getPublicKey(), "BC");
//      Log.i(TAG,"Pubkey for caCertificate: "+ caCertificate.getPublicKey());
//      } catch (CertificateException | NoSuchAlgorithmException | 
//           NoSuchProviderException | InvalidKeyException | SignatureException e)
//            {Log.i(TAG,"Certificate verification exception" + e);}
//

// Do signature verification by decrypting it and comparing to expected
// value (01FFFFFFFFFFFFFFF.....FFFFFF003021300906052B0E03021A05 000414... etc)

byte[] signature = certs[0].getSignature();   // signature in server's certif.
BigInteger exp = new BigInteger("010001",16); // 65537 as usual
BigInteger decrypt_sign = new BigInteger(1, signature).modPow(exp, ca_pubkey.getModulus());
System.out.println("Signature after decryption: " +decrypt_sign);

编辑:我正在覆盖验证过程,因为它没有检测到假证书。查看我的代码版本,现在只需要检查解密值是否符合预期。

见:

http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html

为了很好的解释。

另外,感谢所有提供帮助的人。 :)

【问题讨论】:

    标签: java android exception ssl x509certificate


    【解决方案1】:

    这可能与您正在吃(捕获而不是重新抛出)一堆可能由 certs[0].verify 抛出的异常有关

    【讨论】:

    • 谢谢。正如我之前提到的,代码在 Android 环境(在我的例子中是 NetBeans)之外运行良好,实际上捕获了 SignatureException 并打印到控制台。你还认为我应该修改那部分代码吗?你有什么建议?提前致谢。
    • Android 上的许多加密库都不同 - 请记住,这是与直接 Java 不同的环境。因此,当您在 Android 上时,很可能在不同的地方引发了不同的异常。您应该适当地处理所有异常,永远不要“吃掉”它们。
    • @user4646718 你的android登录里有没有“证书验证异常”的行?
    • @vlp 不,没有,这就是问题所在。无论如何,不​​得不继续这样做,所以我最终决定手动计算它(见编辑)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    • 2012-08-30
    • 2015-11-01
    • 2012-09-08
    • 1970-01-01
    • 2017-05-23
    相关资源
    最近更新 更多