I am trying to connect to an IIS6 box running a godaddy 256bit SSL cert, and I am getting the error :
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Been trying to determine what could be causing that, but drawing blanks right now.
Here is how I am connecting :
HttpsURLConnection conn;
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream());
This question is related to
android
ssl
ssl-certificate
In my case this was happening after update to Android 8.0. The self-signed certificate Android was set to trust was using signature algorithm SHA1withRSA. Switching to a new cert, using signature algorithm SHA256withRSA fixed the problem.
I have had a similar problem and I have completely ruled out the strategy of trusting all sources.
I share here my solution applied to an application implemented in Kotlin
I would first recommend using the following website to obtain information about the certificate and its validity
If it does not appear as an 'Accepted Issuers' in the Android default trust store, we must get that certificate and incorporate it into the application to create a custom trust store
The ideal solution in my case was to create a high-level Trust Manager that combines the custom and the Android default trust store
Here he exposes the high level code used to configure the OkHttpClient that he used with Retrofit.
override fun onBuildHttpClient(httpClientBuild: OkHttpClient.Builder) {
val trustManagerWrapper = createX509TrustManagerWrapper(
arrayOf(
getCustomX509TrustManager(),
getDefaultX509TrustManager()
)
)
printX509TrustManagerAcceptedIssuers(trustManagerWrapper)
val sslSocketFactory = createSocketFactory(trustManagerWrapper)
httpClientBuild.sslSocketFactory(sslSocketFactory, trustManagerWrapper)
}
In this way, I could communicate with the server with a self-signed certificate and with other servers with a certificate issued by a trusted certification entity
This is it, I hope it can help someone.
I know this is a very old article, but I came across this article when trying to solve my trust anchor issues. I have posted how I fixed it. If you have pre-installed your Root CA you need to add a configuration to the manifest.
The error message I was getting was similar but the reason was that the self signed certificate had expired. When the openssl client was attempted, it gave me the reason which was overlooked when I was checking the certificate dialog from firefox.
So in general, if the certificate is there in the keystore and its "VALID", this error will go off.
The Trust anchor error can happen for a lot of reasons. For me it was simply that I was trying to access https://example.com/
instead of https://www.example.com/
.
So you might want to double-check your URLs before starting to build your own Trust Manager (like I did).
I had the same problem while connecting from Android client to Kurento server. Kurento server use jks certificates, so I had to convert pem to it. As input for conversion I used cert.pem file and it lead to such errors. But if use fullchain.pem instead of cert.pem - all is OK.
I know that you don't need to trust all certificates but in my case I had problems with some debugging environments where we had self-signed certificates and I needed a dirty solution.
All I had to do was to change the initialization of the sslContext
mySSLContext.init(null, trustAllCerts, null);
where trustAllCerts
was created like this:
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 {
}
} };
Hope that this will come in handy.
In Gingerbread phones, I always get this error: Trust Anchor not found for Android SSL Connection
, even if I setup to rely on my certificate.
Here is the code I use (in Scala language):
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 _ ?
}
}
}
and here is the connection code:
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)
}
Basically, I setup to trust on my custom certificate. If that fails, then I disable security. This is not the best option, but the only choice I know with old and buggy phones.
This sample code, can be easily translated into Java.
Use https://www.ssllabs.com/ssltest/ to test a domain.
The solution of Shihab Uddin in Kotlin.
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException
object {
val okHttpClient: OkHttpClient
val gson: Gson
val retrofit: Retrofit
init {
okHttpClient = getOkHttpBuilder()
// Other parameters like connectTimeout(15, TimeUnit.SECONDS)
.build()
gson = GsonBuilder().setLenient().create()
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
fun getOkHttpBuilder(): OkHttpClient.Builder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
OkHttpClient().newBuilder()
} else {
// Workaround for the error "Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at".
getUnsafeOkHttpClient()
}
private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts: Array<TrustManager> = arrayOf(
object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate?>?,
authType: String?) = Unit
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate?>?,
authType: String?) = Unit
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
}
)
// Install the all-trusting trust manager
val sslContext: SSLContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
val builder = OkHttpClient.Builder()
builder.sslSocketFactory(sslSocketFactory,
trustAllCerts[0] as X509TrustManager)
builder.hostnameVerifier { _, _ -> true }
builder
} catch (e: Exception) {
throw RuntimeException(e)
}
}
The same error will also appear if you use Glide
, images won't show. To overcome it see Glide - javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found and How to set OkHttpClient for glide.
@GlideModule
class MyAppGlideModule : AppGlideModule() {
val okHttpClient = Api.getOkHttpBuilder().build() // Api is the class written above.
// It is better to create okHttpClient here and not use Api.okHttpClient,
// because their settings may differ. For instance, it can use its own
// `addInterceptor` and `addNetworkInterceptor` that can affect on a read JSON.
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
registry.replace(GlideUrl::class.java, InputStream::class.java,
OkHttpUrlLoader.Factory(okHttpClient))
}
}
build.gradle:
// Glide.
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
Contrary to the accepted answer you do not need a custom trust manager, you need to fix your server configuration!
I hit the same problem while connecting to an Apache server with an incorrectly installed dynadot/alphassl certificate. I'm connecting using HttpsUrlConnection (Java/Android), which was throwing -
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.
The actual problem is a server misconfiguration - test it with http://www.digicert.com/help/ or similar, and it will even tell you the solution:
"The certificate is not signed by a trusted authority (checking against Mozilla's root store). If you bought the certificate from a trusted authority, you probably just need to install one or more Intermediate certificates. Contact your certificate provider for assistance doing this for your server platform."
You can also check the certificate with openssl:
openssl s_client -debug -connect www.thedomaintocheck.com:443
You'll probably see:
Verify return code: 21 (unable to verify the first certificate)
and, earlier in the output:
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`
The certificate chain will only contain 1 element (your certificate):
Certificate chain
0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
i:/O=AlphaSSL/CN=AlphaSSL CA - G2
... but should reference the signing authorities in a chain back to one which is trusted by Android (Verisign, GlobalSign, etc):
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
Instructions (and the intermediate certificates) for configuring your server are usually provided by the authority that issued your certificate, for example: http://www.alphassl.com/support/install-root-certificate.html
After installing the intermediate certificates provided by my certificate issuer I now have no errors when connecting using HttpsUrlConnection.
If you use retrofit, you need to customize your OkHttpClient.
retrofit = new Retrofit.Builder() .baseUrl(ApplicationData.FINAL_URL) .client(getUnsafeOkHttpClient().build()) .addConverterFactory(GsonConverterFactory.create()) .build();
Full code are as below.
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;
}
}
Update based on latest Android documentation (March 2017):
When you get this type of error:
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)
the issue could be one of the following:
The solution is to teach HttpsURLConnection
to trust a specific set of CAs. How? Please check https://developer.android.com/training/articles/security-ssl.html#CommonProblems
Others who are using AsyncHTTPClient
from com.loopj.android:android-async-http
library, please check Setup AsyncHttpClient to use HTTPS.
Replying to very old post. But maybe it will help some newbie and if non of the above works out.
Explanation: I know nobody wants explanation crap; rather the solution. But in one liner, you are trying to access a service from your local machine to a remote machine which does not trust your machine. You request need to gain the trust from remote server.
Solution: The following solution assumes that you have the following conditions met
Steps:
You need a .keystore extension file to signup your app. If you don't know how to create .keystore file; then follow along with the following section Create .keystore file or otherwise skip to next section Sign Apk File
Create .keystore file
Open Android Studio. Click top menu Build > Generate Signed APK. In the next window click the Create new... button. In the new window, please input in data in all fields. Remember the two Password field i recommend should have the same password; don't use different password; and also remember the save path at top most field Key store path:. After you input all the field click OK button.
Sign Apk File
Now you need to build a signed app with the .keystore file you just created. Follow these steps
Choose existing...
buttonKey store password
and Key password
fields. Also enter the aliasbuild.gradle
files, you need to select Build Types
and Flavors
.Build Types
choose release
from the dropdownFor Flavors
however it will depends on your settings in build.gradle
file. Choose staging
from this field. I used the following settings in the build.gradle
, you can use the same as mine, but make sure you change the applicationId
to your package name
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"
}
}
Click the bottom two Signature Versions
checkboxes and click Finish
button.
Almost There:
All the hardwork is done, now the movement of truth. Inorder to access the Staging server backed-up by proxy, you need to make some setting in your real testing Android devices.
Proxy Setting in Android Device:
Modify network
Advanced options
if you can't see the Proxy Hostname
fieldProxy Hostname
enter the host IP or name you want to connect. A typical staging server will be named as stg.api.mygoodcompany.com
9502
Save
buttonOne Last Stop:
Remember we generated the signed apk file in Sign APK File section. Now is the time to install that APK file.
adb install
name of the apk file
adb command not found
. Enter the full path as C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe
install
name of the apk file
I hope the problem might be solved. If not please leave me a comments.
Salam!
**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);
I had the same problem what i found was that the certificate .crt file i provided missing an intermediate certificate. So I asked all .crt files from my server admin, then concatinated them in reverse order.
Ex. 1. Root.crt 2. Inter.crt 3. myCrt.crt
in windows i executed copy Inter.crt + Root.crt newCertificate.crt
(Here i ignored myCrt.crt)
Then i provided newCertificate.crt file into code via inputstream. Work done.
You can trust particular certificate at runtime.
Just download it from server, put in assets and load like this using ssl-utils-android:
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
In the example above I used OkHttpClient
but SSLContext
can be used with any client in Java.
If you have any questions feel free to ask. I'm the author of this small library.
Source: Stackoverflow.com