簡體   English   中英

Android | Google Maps api密鑰和自簽名證書沖突

[英]Android | Google Maps api key and self signed certificate conflict

經過大量的浪費時間后,我發現我的Google Maps api密鑰與我自己簽名的ssl證書沖突。

這是我信任證書的方法

public static void trustSelfSignedSSL() {

        try {
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return hostname.equals(Config.HTTPS_CERTIFICATE_URL);
                    //System.out.println("*************################### " + hostname);
                    //return true;
                }
            });

            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            Context appContext = HBGApplication.context;
            AssetManager assets = appContext.getAssets();
            InputStream caInput = assets.open(Config.HTTPS_CERTIFICATE_ASSETS_FILE);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }

            String 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);

            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);
            HttpsURLConnection.setDefaultSSLSocketFactory(
                    context.getSocketFactory());
        } catch (Exception e) { // should never happen
            e.printStackTrace();
        }
    } 

如果我發表評論,此方法映射將正常工作。 我試圖用verify方法驗證google maps端點,但似乎從來沒有輸入過該方法用於地圖。

所以我的問題是:如何使用我的自簽名證書進行服務通信(不包括地圖服務)?

我找到了一個受此鏈接啟發的解決方案

http://www.javacodegeeks.com/2014/11/how-to-setup-custom-sslsocketfactorys-trustmanager-per-each-url-connection.html

建議使用TrustManager添加自定義SslSocketFactory

好的,我找到了解決方案:

protected static Certificate ca;

/**
     * set self signed certificate to trust
     */
    public static void trustSelfSignedSSL() {

        try {
            // set hostname verifier to check hostname validity
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return hostname.equals(Config.HTTPS_CERTIFICATE_URL) || hostname.equals(Config.HTTPS_GOOGLE_URL);
                }
            });

            // load certificate
            hbgCa = getCert();

            // add certificate to key store
            if (null != hbgCa) {
                String keyStoreType = KeyStore.getDefaultType();
                KeyStore keyStore = KeyStore.getInstance(keyStoreType);
                keyStore.load(null, null);
                keyStore.setCertificateEntry("hbgCa", hbgCa);

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

                SSLContext context = SSLContext.getInstance("TLS");
                context.init(null, tmf.getTrustManagers(), null);
//          HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
                HttpsURLConnection.setDefaultSSLSocketFactory(createSslSocketFactory());
            }
        } catch (Exception e) { // should never happen
            e.printStackTrace();
        }
    }


    /**
     * create a custom sslsocketfactory to trust server connections
     *
     * @return
     * @throws Exception
     */
    private static SSLSocketFactory createSslSocketFactory() throws Exception {
        TrustManager[] byPassTrustManagers = new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                // Loading the CA cert
                if (null == ca) {
                    ca = getCert();
                }

                for (X509Certificate cert : chain) {

                    // check if the certificate is the selfsigned trusted one
                    if (verifiyCertificate(ca, cert)) {
                        return;
                    }
                    // check if current certificate belongs to google
                    if (cert.getIssuerX500Principal().getName().equals("CN=Google Internet Authority G2,O=Google Inc,C=US")) {
                        return;
                    }
                }

        // if none certificate trusted throw certificate exception to tell to not trust connection
                throw new CertificateException();
            }
        }
        };

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, byPassTrustManagers, new SecureRandom());
        return sslContext.getSocketFactory();
    }


    /**
     * verifiy a certificate against the other
     */
    private static boolean verifiyCertificate(Certificate cert1, Certificate cert2) {
        try {
            cert1.verify(cert2.getPublicKey());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * load and return selfsigned local cert
     *
     * @return
     */
    private static Certificate getCert() {

        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Context appContext = HBGApplication.getWrapperContext();
            AssetManager assets = appContext.getAssets();
            InputStream caInput = assets.open(Config.HTTPS_CERTIFICATE_ASSETS_FILE);
            Certificate ca;

            try {
                return cf.generateCertificate(caInput);
            } catch (CertificateException e) {
                e.printStackTrace();
            } finally {
                caInput.close();
            }

            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

為了避免使用默認的SSLSocketFactory,我們有機會實現自定義的TrustManager。 因為我正在開發客戶端,所以我的應用程序應將服務器身份檢查到checkServerTrusted方法中。 通過這種方法,我們獲得了證書,並嘗試針對服務器接收的所有證書鏈進行驗證。 如果驗證失敗,則會引發異常,因此我們可以手動引發CertificateException,指示證書未被接受。 最初,我已經下載了google證書並將其添加到certs隊列中,但是當他的有效期到期時,我的應用將無法再使用。 因此,我決定檢查證書的IssuerX500Principal的名稱是否與Google的名稱匹配。

現在,我可以連接到服務器了,可以使用Google服務。 我已經嘗試將另一個證書更改為測試目的,並且該連接不再受信任,所以我認為它很好用。

如果有人可以建議我一些錯誤,將不勝感激

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM