读入适用于Android App的PKCS12 / P12客户端证书文件

我正在尝试在我的Android应用程序中使用客户端证书,这样我就可以确保只与使用该应用程序或拥有该证书的人员进行HTTPS通信.

我在res / raw文件夹中有证书.当我开始输入“R.raw”时,Android Studio会看到它.

但是,当我使用以下任何代码时,变量返回为具有“null”值:

FileInputStream fis = null;
fis = (FileInputStream) getClass().getResourceAsStream(String.valueOf(R.raw.clientcert2));

要么

InputStream fis = getClass().getResourceAsStream("raw/clientcert2.p12");

要么

InputStream fis = null;
fis= (InputStream) getResources().openRawResource(R.raw.clientcert2);

最后一个实际上崩溃了应用程序,这让我觉得它甚至没有接近正确.它崩溃时出现以下错误:

09-10 08:13:06.677  10310-10310/com.example.agenice.clientcert E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.agenice.clientcert, PID: 10310
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.agenice.clientcert/com.example.agenice.clientcert.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.NullPointerException
at android.content.ContextWrapper.getResources(ContextWrapper.java:89)
at android.view.ContextThemeWrapper.getResources(ContextThemeWrapper.java:78)
at com.example.agenice.clientcert.GetCert.getThisCert(MainActivity.java:92)
at com.example.agenice.clientcert.MainActivity.onCreate(MainActivity.java:58)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)

作为旁注 – 是的,我知道如果有人获得APK,他们可以简单地解压缩包并获取证书.这就是为什么这不是应用程序的最终形式.这只是过程中的第一步.在iOS版本的App中,我能够导入p12文件,将二进制文件转换为字符串,将字符串导出到日志中,然后将其用作证书.这消除了将证书文件添加到应用程序的需要.所以,这就是整个事情的发展方向.如果有人能够快速简便地做到这一点,那就太好了.现在,我只需要弄清楚为什么这部分不起作用.

谢谢!

最佳答案
更新您的NullPointerException

根据您的logcat信息,GetCert.getThisCert()中的getResources()导致NullPointerException.看起来您没有将Context从您的Activity传递给GetCert类.因此,请更新您的代码并检查结果.

更新结束

您可以参考我的以下代码:

private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
        final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
        return new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return originalTrustManager.getAcceptedIssuers();
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        try {
                            originalTrustManager.checkClientTrusted(certs, authType);
                        } catch (CertificateException e) {
                            e.printStackTrace();
                        }
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        try {
                            originalTrustManager.checkServerTrusted(certs, authType);
                        } catch (CertificateException e) {
                            e.printStackTrace();
                        }
                    }
                }
        };
    }

private SSLSocketFactory getSSLSocketFactory_Certificate(String keyStoreType, int keystoreResId)
        throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = getResources().openRawResource(keystoreResId);

    Certificate ca = cf.generateCertificate(caInput);
    caInput.close();

    if (keyStoreType == null || keyStoreType.length() == 0) {
        keyStoreType = KeyStore.getDefaultType();
    }
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, wrappedTrustManagers, null);

    return sslContext.getSocketFactory();
}

private SSLSocketFactory getSSLSocketFactory_KeyStore(String keyStoreType, int keystoreResId, String keyPassword)
            throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {

        InputStream caInput = getResources().openRawResource(keystoreResId);

        // creating a KeyStore containing trusted CAs

        if (keyStoreType == null || keyStoreType.length() == 0) {
            keyStoreType = KeyStore.getDefaultType();
        }
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);

        keyStore.load(caInput, keyPassword.toCharArray());

        // creating a TrustManager that trusts the CAs in the KeyStore

        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, wrappedTrustManagers, null);

        return sslContext.getSocketFactory();
    }

然后调用以下两个中的一个(一个用于密钥库文件,另一个用于证书文件):

SSLSocketFactory sslSocketFactory = getSSLSocketFactory_KeyStore("BKS", R.raw.androidbksv1, "123456789");
SSLSocketFactory sslSocketFactory = getSSLSocketFactory_Certificate("BKS", R.raw.androidbksv1_cert);

因为您有PKCS12文件,所以可以使用以下两种方法之一:

SSLSocketFactory sslSocketFactory = getSSLSocketFactory_KeyStore("PKCS12", R.raw.androidpkcs12, "123456789");        
SSLSocketFactory sslSocketFactory = getSSLSocketFactory_Certificate("PKCS12", R.raw.androidpkcs12_cert);

上面的代码已在我的HTTPS项目中成功测试过.希望这可以帮助!

此外,请澄清最后一个实际上崩溃应用程序…,发布更多代码和logcat信息(如果可用).

转载注明原文:读入适用于Android App的PKCS12 / P12客户端证书文件 - 代码日志