web-dev-qa-db-ja.com

Android SSL接続に信頼アンカーが見つかりません

Godaddy 256bit SSL証明書を実行しているIIS 6ボックスに接続しようとしていますが、エラーが発生しています。

Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

何が原因となっているのかを突き止めようとしていましたが、今は空白を描画しています。

これが私が接続している方法です:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream()); 
144
Chrispix

@Chrispixの解決策は危険です! すべての証明書を信頼すれば、誰でも攻撃を仕掛けることができます!証明書をクライアントに送信するだけで、それが受け入れられます。

この記事で説明しているように、カスタムの信頼マネージャに証明書を追加します。 HTTPS経由でHttpClientを使用してすべての証明書を信頼する

カスタム証明書を使用して安全な接続を確立するのは少し複雑ですが、中間攻撃の危険なしに、必要なSSL暗号化セキュリティを実現できます。

64
Matthias B

承認された回答とは反対にしないカスタムの信頼マネージャは必要ありません、サーバーを修正する必要があります構成!

正しくインストールされていないdynadot/alphassl証明書を使用してApacheサーバーに接続しているときに同じ問題が発生しました。投げていたHttpsUrlConnection(Java/Android)を使って接続しています -

javax.net.ssl.SSLHandshakeException: 
  Java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

実際の問題はサーバの設定ミスです - http://www.digicert.com/help/ かそれに類似したものでテストしてください。

「証明書は信頼できる機関によって署名されていません(Mozillaのルートストアと照合)。信頼できる機関から証明書を購入した場合は、おそらくインストールする必要があります。 1つ以上の中間証明書。ご使用のサーバープラットフォームでこれを行うには、証明書プロバイダにお問い合わせください。」

Opensslで証明書を確認することもできます。

openssl s_client -debug -connect www.thedomaintocheck.com:443

あなたはおそらく見えるでしょう:

Verify return code: 21 (unable to verify the first certificate)

そして、出力の早い方で:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

証明書チェーンに含まれる要素は1つだけです(あなたの証明書)。

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

...しかし、Androidによって信頼されている機関(Verisign、GlobalSignなど)にチェーンで署名機関を参照する必要があります。

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

サーバーを構成するための指示(および中間証明書)は、通常、証明書を発行した機関によって提供されます。例えば、 http://www.alphassl.com/support/install-root-certificate.html =

証明書の発行者から提供された中間証明書をインストールした後、HttpsUrlConnectionを使用して接続するときにエラーが発生しなくなりました。

188
Stevie

実行時に特定の証明書を信頼することができます。
サーバーからダウンロードし、アセットに入れて ssl-utils-Android を使用してこのようにロードするだけです。

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

上記の例ではOkHttpClientを使用しましたが、SSLContextはJavaのどのクライアントでも使用できます。

ご質問がありましたらお気軽にお尋ねください。私はこの小さな図書館の作者です。

16
klimat

最新のAndroidドキュメント(2017年3月)に基づく更新:

このようなエラーが発生した場合

javax.net.ssl.SSLHandshakeException: Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:374)
        at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.Java:209)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:478)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.Java:433)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.Java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.Java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.Java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.Java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.Java:271)

問題は次のいずれかです。

  1. サーバー証明書を発行したCAが不明です
  2. サーバー証明書はCAによって署名されていませんが、自己署名されています
  3. サーバー構成に中間CAがありません

解決策は、特定のCAのセットを信頼するようにHttpsURLConnectionを教えることです。どうやって?チェックしてください https://developer.Android.com/training/articles/security-ssl.html#CommonProblems

com.loopj.Android:android-async-httpライブラリのAsyncHTTPClientを使用している他の人は、 HTTPSを使用するようにAsyncHttpClientを設定 を確認してください。

11
user1506104

非常に古い投稿に返信しています。しかし、多分それはいくつかの初心者を助け、上記のどれでも解決しないならば。

説明:私は誰も説明がらくたを望んでいないことを知っています。むしろ解決策です。しかし、あるライナーでは、あなたはあなたのローカルマシンからあなたのマシンを信頼しないリモートマシンへのサービスにアクセスしようとしています。あなたはリモートサーバーから信頼を得る必要があると要求します。

Solution:以下の解決策はあなたが以下の条件を満たしていることを前提としています

  1. ローカルコンピュータからリモートAPIにアクセスしようとしています。
  2. あなたはAndroidアプリのために構築しています
  3. あなたのリモートサーバはプロキシフィルタリングされています(あなたはリモートapiサービスにアクセスするためにあなたのブラウザ設定でプロキシを使います、典型的にはステージングまたはデベロッパーサーバです)
  4. 実際の機器でテストしています

ステップ数

アプリにサインアップするには、.keystore拡張子ファイルが必要です。 .keystoreファイルの作成方法がわからない場合その後、次の手順に従ってくださいセクション.keystoreファイルを作成するまたはそうでなければ次のセクションにスキップします署名APKファイル

.keystoreファイルを作成する

Android Studioを開きます。トップメニュー[構築]> [署名付きAPKの生成]をクリックします。次のウィンドウでCreate new ...ボタンをクリックしてください。新しいウィンドウで、すべてのフィールドにデータを入力してください。 2つのパスワードフィールドを覚えておいてください。私は同じパスワードを使うべきです。別のパスワードを使用しないでください。また、一番上のフィールドの保存パスも覚えておいてくださいKey store path:。すべてのフィールドを入力したら、[OK]ボタンをクリックしてください。

Sign Apk File

これで、作成したばかりの.keystoreファイルを使用して署名付きアプリを構築する必要があります。次の手順を実行します

  1. 「構築」>「プロジェクトのクリーン」を選択し、クリーンになるまで待ちます
  2. ビルド>署名付きAPKの生成
  3. Choose existing...ボタンをクリック
  4. Create .keystoreファイルセクションで作成したばかりの.keystoreファイルを選択します。
  5. 作成時に作成したものと同じパスワードをCreate .keystoreファイルセクションに入力します。 Key store passwordフィールドとKey passwordフィールドに同じパスワードを使用してください。別名も入力してください
  6. 次へボタンをクリック
  7. 次の画面でこれはbuild.gradleファイルの設定によって異なる場合がありますので、Build TypesFlavorsを選択する必要があります。
  8. Build Typesについては、ドロップダウンからreleaseを選択してください。
  9. Flavorsの場合は、build.gradleファイルの設定によって異なります。このフィールドからstagingを選択してください。私はbuild.gradleで以下の設定を使用しました、あなたは私のと同じを使用することができます、しかしあなたがあなたのパッケージ名にapplicationIdを変更することを確認してください

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
    
  10. 下の2つのSignature VersionsチェックボックスをクリックしてFinishボタンをクリックします。

ほぼあります

すべてのハードワーク、今真実の動きが行われています。プロキシでバックアップされたステージングサーバーにアクセスするには、実際のテスト用Androidデバイスで何らかの設定を行う必要があります。

Androidデバイスのプロキシ設定:

  1. Android携帯内の設定をクリックしてからWi - Fiを
  2. 接続した無線LANを長押ししてModify networkを選択
  3. Advanced optionsフィールドが表示されない場合は、Proxy Hostnameをクリックしてください。
  4. Proxy Hostnameに、接続したいホストIPまたは名前を入力します。一般的なステージングサーバーはstg.api.mygoodcompany.comという名前になります。
  5. ポートには、4桁のポート番号を入力します(例:9502)。
  6. Saveボタンを押す

最後の1駅

署名したapkファイルをSign APK Fileセクションに生成したことを忘れないでください。今がそのAPKファイルをインストールする時です。

  1. 端末を開き、署名されたapkファイルフォルダに移動します
  2. あなたのAndroidデバイスをあなたのマシンに接続する
  3. Androidデバイスから以前にインストールしたapkファイルを削除します。
  4. adb installを実行します。name of the apk file
  5. 何らかの理由で上記のコマンドがadb command not foundを返す場合。フルパスをC:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exeinstallname of the apk fileとして入力します

問題が解決することを願っています。そうでなかったら私にコメントを残しなさい。

サラム!

7
HA S

私が得ていたエラーメッセージは似ていました、しかしその理由は自己署名証明書が期限切れだったということでした。 opensslクライアントが試みられたとき、それは私がFirefoxから証明書ダイアログをチェックしていたときに見落とされていた理由を私に与えました。

そのため、一般的に、証明書がキ​​ーストアに存在し、その「有効」であれば、このエラーは発生しません。

4
MPN

後付けを使用する場合は、OkHttpClientをカスタマイズする必要があります。

retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

完全なコードは以下の通りです。

    public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new Java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ApiInterface getApiClient() {
        if (apiInterface == null) {

            try {
                retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

            } catch (Exception e) {

                e.printStackTrace();
            }


            apiInterface = retrofit.create(ApiInterface.class);
        }
        return apiInterface;
    }

}
4
Shihab Uddin

AndroidクライアントからKurentoサーバーへの接続中に同じ問題が発生しました。 Kurentoサーバーはjks証明書を使うので、pemをそれに変換する必要がありました。変換のための入力として私はcert.pemファイルを使いました、そしてそれはそのようなエラーを引き起こします。しかし、cert.pemの代わりにfullchain.pemを使用すれば、すべて問題ありません。

3
V.Poddubchak

私はあなたがすべての証明書を信頼する必要はないことを知っていますが、私の場合私たちが自己署名証明書を持っていたいくつかのデバッグ環境で問題を抱えていました。

私がしなければならなかったのはsslContextの初期化を変更することだけでした

mySSLContext.init(null, trustAllCerts, null); 

trustAllCertsは次のように作成されています。

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new Java.security.cert.X509Certificate[]{};
    }

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

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

これが便利になることを願っています。

2
Adrian C.

私が見つけたものと同じ問題を抱えていたのは、証明書.crtファイルに中間証明書がないことです。だから私は私のサーバー管理者からすべての.crtファイルを尋ねて、それからそれらを逆の順序で連結した。

例1. Root.crt 2. Inter.crt 3. myCrt.crt

windowsで私はコピーInter.crt + Root.crt newCertificate.crtを実行しました

(ここで私はmyCrt.crtを無視しました)

それから私は入力ストリームを介してコードにnewCertificate.crtファイルを提供しました。仕事は終わった。

2
sahan maldeniya

トラストアンカーエラーは多くの理由で発生する可能性があります。私にとっては、単にhttps://example.com/ではなくhttps://www.example.com/にアクセスしようとしているだけでした。

ですから、私がやったようにあなた自身のトラストマネージャを構築し始める前にあなたのURLを再確認したいかもしれません。

1
Unkulunkulu

ジンジャーブレッド電話では、私はいつもこのエラーを受け取ります:私が私の証明書に頼るように設定したとしても、Trust Anchor not found for Android SSL Connection.

これが私が使うコードです(Scala言語で):

object Security {
    private def createCtxSsl(ctx: Context) = {
        val cer = {
            val is = ctx.getAssets.open("mycertificate.crt")
            try
                CertificateFactory.getInstance("X.509").generateCertificate(is)
            finally
                is.close()
        }
        val key = KeyStore.getInstance(KeyStore.getDefaultType)
        key.load(null, null)
        key.setCertificateEntry("ca", cer)

        val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    tmf.init(key)

        val c = SSLContext.getInstance("TLS")
        c.init(null, tmf.getTrustManagers, null)
        c
    }

    def prepare(url: HttpURLConnection)(implicit ctx: Context) {
        url match {
            case https: HttpsURLConnection ⇒
                val cSsl = ctxSsl match {
                    case None ⇒
                        val res = createCtxSsl(ctx)
                        ctxSsl = Some(res)
                        res
                    case Some(c) ⇒ c
                }
                https.setSSLSocketFactory(cSsl.getSocketFactory)
            case _ ⇒
        }
    }

    def noSecurity(url: HttpURLConnection) {
        url match {
            case https: HttpsURLConnection ⇒
                https.setHostnameVerifier(new HostnameVerifier {
                    override def verify(hostname: String, session: SSLSession) = true
                })
            case _ ⇒
        }
    }
}

これが接続コードです。

def connect(securize: HttpURLConnection ⇒ Unit) {
    val conn = url.openConnection().asInstanceOf[HttpURLConnection]
    securize(conn)
    conn.connect();
    ....
}

try {
    connect(Security.prepare)
} catch {
    case ex: SSLHandshakeException /*if ex.getMessage != null && ex.getMessage.contains("Trust anchor for certification path not found")*/ ⇒
        connect(Security.noSecurity)
}

基本的に、私は私のカスタム証明書を信頼するように設定しました。それが失敗した場合、私はセキュリティを無効にします。これは最良の選択肢ではありませんが、私が古くてバグのある電話で知っている唯一の選択肢です。

このサンプルコードは、簡単にJavaに翻訳できます。

0
david.perez

私の場合、これはAndroid 8.0へのアップデート後に起こっていました。 Androidが信頼するように設定された自己署名証明書は、署名アルゴリズムSHA1withRSAを使用していました。署名アルゴリズムSHA256withRSAを使用して新しい証明書に切り替えると、問題が解決しました。

0
Zds