没有以前的internet连接,无法验证Android自签名证书

没有以前的internet连接,无法验证Android自签名证书,android,ssl,https,certificate,self-signed,Android,Ssl,Https,Certificate,Self Signed,工作的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.toCharA

工作的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();
javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not     validate certificate: null
我们有一个有效的客户机/服务器设置,Android版本为4.2和4.4的手机充当客户机,必须通过自签名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();
javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not     validate certificate: null
只要设备在尝试连接之前至少访问过一次internet,服务器证书验证就可以工作。但是,如果执行出厂重置,并且设备直接连接到专用网络而没有internet连接,则证书验证失败

要复制该行为,请执行以下操作:

  • 工厂重置手机
  • 重新启动,无需选择连接到具有互联网接入的WiFi
  • 尝试验证自签名SSL证书->失败
  • 通过互联网接入连接到WiFi
  • 重新连接到原始专用网络
  • 尝试验证自签名SSL证书->是否有效
  • 从技术上讲,设备不需要访问互联网来验证自签名证书。在进行任何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();
    
    javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not     validate certificate: null
    
    失败,startHandshake中出现异常:

        //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();
    
    javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not     validate certificate: null
    

    确保设备上的时间正确,证书具有有效期,并且如果将日期设置为过去(通常是工厂重置后的2000年1月1日)或未来,证书将不会生效。该设备将通过NTP自动同步,但当没有可用的Internet连接时,这显然不起作用

    您对HTTP请求使用什么<代码>网络视图<代码>HttpUrlConnection<代码>确定http<代码>HttpClient?还有什么吗?我正在构建自己的SSLContext来创建具有特定信任库和密钥库的SSLSockets。如果跳过第2步和第3步,第一次尝试是否有效?您看,您确定这不是首次使用失败,而是没有互联网接入失败吗?您的具体测试设备是什么?您是否能够在SDK的模拟器上重现此问题(在仅连接到专用网络的开发机器上运行)?如果我在连接到专用服务器之前访问过一次internet,它可以正常工作,但您的设备上的时间对吗?查看
    RFC3280CertPathUtilities.java
    ,此消息仅针对过期/尚未生效的证书生成。如果您没有Internet,设备无法与NTP同步时间,因此很可能日期设置为2000年或类似的日期。很好的发现。该死,我已经被它咬了很多次了,我都数不清。。。但通常是通过蜂窝无线电(无Wifi/BT)。我很惊讶它没有向我扑来。