如果没有先前的互联网连接,则无法验证 Android 自签名证书

标签 android ssl https certificate self-signed

有效的 SSL 基础设施:

我们有一个有效的客户端/服务器设置,其中装有 Android 4.2 和 4.4 版的手机充当客户端,必须通过其自签名 SSL 证书验证服务器。

问题:

只要设备在尝试连接之前至少访问过一次互联网,服务器证书验证就会起作用。但是,如果执行出厂重置并且设备直接连接到没有互联网连接的专用网络,则证书验证失败。

要重现该行为:

  1. 将手机恢复出厂设置
  2. 重新启动而不选择连接到具有互联网访问权限的 WiFi
  3. 尝试验证自签名 SSL 证书 -> 失败
  4. 连接到可访问互联网的 WiFi
  5. 重新连接到原来的专用网络
  6. 尝试验证自签名 SSL 证书 -> WORKS

从技术上讲,设备不需要互联网访问来验证自签名证书。在任何 SSL 服务器验证发生之前,是否有某种必须加载一次的黑名单?我可以阻止这种行为吗?

创建 SSL 上下文:

    //Using a client certificate
    String password = "clientpass";
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    InputStream is = context.getResources().openRawResource(R.raw.client);
    keyStore.load(is, password.toCharArray());
    is.close();
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
    kmf.init(keyStore, password.toCharArray());
    KeyManager[] keyManagers = kmf.getKeyManagers();


    // Using self signed certificate
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    is = context.getResources().openRawResource(R.raw.cacert);
    InputStream caInput = new BufferedInputStream(is);
    Certificate ca;
    try {
        ca = cf.generateCertificate(caInput);
        Log.i("CA","ca=" + ((X509Certificate) ca).getSubjectDN());
    } finally {
        caInput.close();
    }

    // Create a KeyStore containing our trusted CAs
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    trustStore.load(null);
    trustStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
    tmf.init(trustStore);
    TrustManager[] trustManagers = tmf.getTrustManagers();

    // Create an SSLContext that uses our Trustmanager and Keymanager
    SSLContext sslcontext = SSLContext.getInstance("TLS");

    sslcontext.init(keyManagers, trustManagers, null);

    //create a socket to connect with the server
    SSLSocketFactory socketFactory = sslContext.getSocketFactory();
    SSLSocket socket = (SSLSocket) socketFactory.createSocket(serverAddr, port);
    socket.setUseClientMode(true);
    socket.addHandshakeCompletedListener(this);
    socket.startHandshake();

失败并出现 startHandshake 异常:

javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not     validate certificate: null

最佳答案

确保设备上的时间正确,证书有有效期,并且不会验证日期是否设置为过去(通常是恢复出厂设置后的 2000 年 1 月 1 日)或 future 。该设备将通过 NTP 自动同步,但当没有可用的互联网连接时,这显然不起作用。

关于如果没有先前的互联网连接,则无法验证 Android 自签名证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25265695/

相关文章:

android - 正确检测 Android 设备类型

安卓6.0 : Get package name of current activity

android - 如何在Android中对中文进行排序?

java - 需要帮助使用证书文件运行 Spring restTemplate - 无法找到请求目标的有效证书路径

.htaccess、mod_rewrite 和 SSL 子域重定向

google-chrome - Chrome 在非 ssl heroku web 应用程序上强制使用 ssl

java - ExoPlayer 创建的视频播放器无法正常工作

codeigniter,在特定页面上强制使用 ssl

node.js - nodejs集群不同的TLS Session处理

php - Wordpress(WooCommerce?)强制使用 https(当它不应该时)