【问题标题】:Android to server communication using SSL with Bouncy CastleAndroid 与使用 SSL 和 Bouncy Castle 的服务器通信
【发布时间】:2023-03-12 23:21:01
【问题描述】:

我知道这不是那么困难,但很不幸,我从昨天开始就被困在这里并与之抗争,我一直遵循这个Mutual Authentication in Android 教程,在资源中放置一个密钥库并尝试通过 SSL 连接到我的服务器,但得到以下异常

java.lang.RuntimeException: org.spongycastle.jcajce.provider.asymmetric.x509.CertificateFactory$ExCertificateException

我已将我的sslapptruststore.pfx 文件放在res/raw/sslapptruststore.pfx 下 并使用这段代码

try {

                           KeyStore clientCert = KeyStore.getInstance("PKCS12");
                                   clientCert.load(getResources().openRawResource(R.raw.sslapptruststore), "123456".toCharArray());// this line causes exception

                            HttpClient httpClient = null;
                            HttpParams httpParams = new BasicHttpParams();
                            SSLSocketFactory sslSocketFactory = new SSLSocketFactory(clientCert, null, null);
                            SchemeRegistry registry = new SchemeRegistry();
                            registry.register(new Scheme("https", sslSocketFactory, 8443));
                            httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(httpParams, registry), httpParams);


                            HttpPost httpPost = new HttpPost(
                                    "https://192.168.1.113:8443/CertProvider");
                            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
                            List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(2);
                            nameValuePair.add(new BasicNameValuePair("csr", csr.toString()));

                            // Url Encoding the POST parameters
                                httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));

                            // Making HTTP Request
                            // HttpResponse response = null;
                            ResponseHandler<String> responseHandler = new BasicResponseHandler();
                            String response = "";
                            response = httpClient.execute(httpPost, responseHandler);
                                } catch (Exception e) {
                                    Log.e("", e.getMessage());
                                }

我也搜索过,但其他人正在使用.bks

感谢任何帮助。

【问题讨论】:

    标签: java android ssl bouncycastle spongycastle


    【解决方案1】:

    我已经回答了一些看起来像你的问题如下:

    Read in PKCS12/P12 Client Cert file for Android App

    Android volley self signed HTTPS trust anchor for certification path not found

    你会发现

        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();
        }
    

    getSSLSocketFactory_Certificate 用于.cert 文件。

    和上面的第一个链接一样,在您的项目中,您可以调用以下两种方法之一:

    如果使用密钥库文件:

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

    如果使用证书文件:

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

    P/S:如果这些方法位于非活动类中,为避免 NPE,您必须将 Activity 中的 Context 传递给该类(如上面第一个链接中所示)。

    希望这会有所帮助!

    【讨论】:

    • 如果不工作,请告诉我。然后,如果可能的话,向我提供你的 .pfx 文件,以便我可以签入我的项目:)
    • 以前我只将签名证书放入密钥库,但我尝试使用具有完整链的密钥库,它可以工作并且至少能够加载密钥库,但现在出现此异常 >
    • 您的密钥库/证书文件是如何创建的?我使用 Keystore Explorer 创建文件。
    • 我已经通过对代码的一些修改解决了这个问题,我已经更新了
    • 很高兴您解决了您的问题,感谢分享:)
    【解决方案2】:

    我添加了以下类来解决这个问题

    import org.apache.http.conn.ssl.SSLSocketFactory;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.Socket;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.Arrays;
    
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.TrustManagerFactory;
    import javax.net.ssl.X509TrustManager;
    
    /**
     * Allows you to trust certificates from additional KeyStores in addition to
     * the default KeyStore
     */
    public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory{
        protected SSLContext sslContext = SSLContext.getInstance("TLSv1");
    
        public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
            super(null, null, null, null, null, null);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory
                    .getInstance(KeyManagerFactory.getDefaultAlgorithm());;
            keyManagerFactory.init(keyStore, "123456".toCharArray());
            sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[]{new AdditionalKeyStoresTrustManager(keyStore)}, null);
        }
    
        @Override
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
        }
    
        @Override
        public Socket createSocket() throws IOException {
            return sslContext.getSocketFactory().createSocket();
        }
    
    
    
        /**
         * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
         */
        public static class AdditionalKeyStoresTrustManager implements X509TrustManager {
    
            protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();
    
    
            protected AdditionalKeyStoresTrustManager(KeyStore... additionalkeyStores) {
                final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();
    
                try {
                    // The default Trustmanager with default keystore
                    final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    original.init((KeyStore) null);
                    factories.add(original);
    
                    for( KeyStore keyStore : additionalkeyStores ) {
                        final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                        additionalCerts.init(keyStore);
                        factories.add(additionalCerts);
                    }
    
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
    
    
    
                /*
                 * Iterate over the returned trustmanagers, and hold on
                 * to any that are X509TrustManagers
                 */
                for (TrustManagerFactory tmf : factories)
                    for( TrustManager tm : tmf.getTrustManagers() )
                        if (tm instanceof X509TrustManager)
                            x509TrustManagers.add( (X509TrustManager)tm );
    
    
                if( x509TrustManagers.size()==0 )
                    throw new RuntimeException("Couldn't find any X509TrustManagers");
    
            }
    
            /*
             * Delegate to the default trust manager.
             */
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0);
                defaultX509TrustManager.checkClientTrusted(chain, authType);
            }
    
            /*
             * Loop over the trustmanagers until we find one that accepts our server
             */
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                for( X509TrustManager tm : x509TrustManagers ) {
                    try {
                        tm.checkServerTrusted(chain,authType);
                        return;
                    } catch( CertificateException e ) {
                        // ignore
                    }
                }
                throw new CertificateException();
            }
    
            public X509Certificate[] getAcceptedIssuers() {
                final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
                for( X509TrustManager tm : x509TrustManagers )
                    list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
                return list.toArray(new X509Certificate[list.size()]);
            }
        }
    
    }
    

    【讨论】:

    • 我也有同样的问题。我的代码在 CertificateFactory cf = CertificateFactory.getInstance("X.509","BC") 行中给出错误。我怎样才能使用这个类来避免错误?谢谢
    • @Hilal 分享你的错误跟踪,大致我可以建议你检查你的提供者列表,可能是 BC 提供者不在列表中
    • 我无法粘贴整个错误,因为 stackoverflow 不允许:) 另外我如何检查提供商列表?这是错误; com.android.org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory$ExCertificateException 09-20 12:48:02.042 20236-20350/com.example.hilalinan.cert W/System.err:在 com.android.org .bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory.engineGenerateCertificate(CertificateFactory.java:220) 09-20 12:48:02.042 20236-20350/com.example.hilalinan.cert W/System.err:
    • 我发现了如何检查提供者列表并且在列表中看不到 BC。但是我尝试了其他而不是 BC 但后来我得到了 NoSuchProviderException。例如:ACCVRAIZ1 我认为我应该编写它们的代码版本但是不知道在哪里可以找到?有共同名称、组织、组织单位、序列号等字段。他们都不适合我
    • @Hilal 实际上 android 只能与 BC 一起使用,所以我认为它很适合 chng 提供者,而不是你必须将 BC 添加到列表中,不幸的是我还没有发送该代码,你可以谷歌如何将 BC 添加到列表中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多