Обновление на основе последней документации для Android (март 2017 года):
Когда вы получаете этот тип ошибки:
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)
проблема может быть одной из следующих:
Решение состоит в том, чтобы научить HttpsURLConnection
доверять определенному набору ЦС. Как? Пожалуйста, проверьте https://developer.android.com/training/articles/security-ssl.html#CommonProblems
Другие, которые используют AsyncHTTPClient
из библиотеки com.loopj.android:android-async-http
проверьте Настройка AsyncHttpClient для использования HTTPS .
В телефонах Gingerbread я всегда получаю эту ошибку: 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.
**Set proper alias name**
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
String alias = cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
Ответ на очень старый пост. Но, возможно, это поможет новичку, и если не выйдет из вышеизложенного,
Объяснение: Я знаю, что никто не хочет объяснять дерьмо; скорее решение. Но в одном лайнере вы пытаетесь получить доступ к службе с вашей локальной машины на удаленную машину, которая не доверяет вашей машине. Вы требуете получить доверие от удаленного сервера.
Решение. Следующее решение предполагает, что у вас есть следующие условия:
Шаги:
Вам нужен файл расширения .keystore для регистрации вашего приложения. Если вы не знаете, как создать файл .keystore; затем следуйте следующему разделу Создание файла .keystore или иначе перейдите к следующему разделу. Подпишите файл Apk
Создайте файл .keystore
Откройте Android Studio. Нажмите верхнее меню «Сборка»> «Создать подписанный АПК». В следующем окне нажмите кнопку «Создать новый ...». В новом окне введите данные во все поля. Помните, что два поля Password, которые я рекомендую, должны иметь один и тот же пароль; не используйте другой пароль; а также запомнить путь сохранения в верхней части поля. После ввода всего поля нажмите кнопку OK.
Подпишите файл Apk
Теперь вам нужно создать подписанное приложение с только что созданным файлом .keystore. Выполните следующие шаги
Choose existing...
Key store password
и Key password
. Также введите псевдоним build.gradle
, вам нужно выбрать Build Types
и Flavors
. Build Types
выберите release
из выпадающего меню 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"
}
}
Signature Versions
и нажмите кнопку Finish
. Почти там:
Все трудолюбие сделано, теперь движение истины. Чтобы получить доступ к промежуточному серверу, поддерживаемому прокси-сервером, вам нужно сделать некоторые настройки на реальных Android-устройствах.
Настройки прокси-сервера в Android-устройстве:
Modify network
Advanced options
, если вы не видите поле Proxy Hostname
Proxy Hostname
введите IP-адрес хоста или имя, которое вы хотите подключить. Типичный промежуточный сервер будет называться как stg.api.mygoodcompany.com
9502
Save
One Last Stop:
Помните, что мы сгенерировали подписанный файл apk в разделе Sign APK File. Настало время установить этот файл APK.
adb install
name of the apk file
adb command not found
. Введите полный путь как C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe
install
name of the apk file
Надеюсь, что проблема может быть решена. Если нет, оставьте мне комментарии.
Салам!
Вы можете доверять определенному сертификату во время выполнения. Просто загрузите его с сервера, введите активы и загрузите, как это, используя ssl-utils-android :
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
В приведенном выше примере я использовал OkHttpClient
, но SSLContext
может использоваться с любым клиентом на Java.
Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать. Я автор этой небольшой библиотеки.
Сообщение об ошибке, которое я получал, было похоже, но причина в том, что срок действия подписанного сертификата уже истек. Когда клиент openssl был предпринят попытка, он дал мне причину, которая была упущена, когда я проверял диалоговое окно сертификата из firefox.
Итак, если сертификат существует в хранилище ключей и его «VALID», эта ошибка исчезнет.
У меня была та же проблема, что я обнаружил, так это то, что в файле сертификата .crt i отсутствует промежуточный сертификат. Поэтому я попросил все .crt-файлы с моего администратора сервера, а затем объединил их в обратном порядке.
Пример. 1. Root.crt 2. Inter.crt 3. myCrt.crt
в windows i выполнил копию Inter.crt + Root.crt newCertificate.crt
(Здесь я проигнорировал myCrt. crt)
Затем я предоставил файл newCertificate.crt в код через входной поток. Работа выполнена.
В отличие от принятого вами ответа, вам не нужен пользовательский менеджер доверия, вам нужно исправить конфигурацию вашего сервера!
Я столкнулся с той же проблемой при подключении к серверу Apache с неправильно установленным сертификатом dynadot / alphassl. Я подключаюсь с использованием HttpsUrlConnection (Java / Android), который метался -
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.
. Фактическая проблема - неправильная конфигурация сервера - проверьте ее с помощью http://www.digicert.com/ help / или аналогичный, и он даже скажет вам решение:
«Сертификат не подписан доверенным органом (проверка на корневой магазин Mozilla). Если вы купили сертификат из (g3) вам, вероятно, просто нужно установить один или несколько промежуточных сертификатов . Обратитесь к поставщику сертификатов за помощью для этого для вашей серверной платформы. »
Вы также можете проверить сертификат с помощью 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`
Цепочка сертификатов будет содержать только один элемент (ваш сертификат):
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.
Ошибка привязки Trust может произойти по многим причинам. Для меня это было просто, что я пытался получить доступ к https://example.com/
вместо https://www.example.com/
.
Таким образом, вы можете дважды проверить свои URL-адреса, прежде чем приступать к созданию собственного Trust Manager (как и я) .
У меня была такая же проблема при подключении с Android-клиента на сервер Kurento. Сервер Kurento использует сертификаты jks, поэтому мне пришлось преобразовать pem в него. В качестве ввода для преобразования я использовал файл cert.pem и приводил к таким ошибкам. Но если использовать fullchain.pem вместо cert.pem - все в порядке.
В моем случае это произошло после обновления до Android 8.0. Самозаверяющему сертификату Android было доверено использовать алгоритм подписи SHA1withRSA. Переключение на новый сертификат с использованием алгоритма подписи SHA256withRSA устранило проблему.