AWS IOT Just-in-Time Registration of Certificate in Android - android

I am integrating the JITR by follwing this article.
https://aws.amazon.com/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/
I am done with all these steps and able to authenticate the certificate through command-line 'mosquitto_pub'.
First time when I run 'mosquitto_pub' command it calls lambda function to authorize it and attach policy and second time it publish message to IOT successfully.
Here is command that I am using.
mosquitto_pub --cafile ../root.cert --cert hassanAndCACert.crt --key hassan.key -h <###>.iot.us-east-1.amazonaws.com
-p 8883 -q 1 -t topic5 -i 123456789 --tls-version tlsv1.2 -m '{"hello":"3"}' -d
But when I try to authenticate this in android SDK I am getting 'handshake' fail error. Here is exception that I am getting.
MqttException (0) - javax.net.ssl.SSLHandshakeException: Handshake
failedat
org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)at
org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:664)at
java.lang.Thread.run(Thread.java:818)Caused by:
javax.net.ssl.SSLHandshakeException: Handshake failedat
com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:441)at
org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:93)at
org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:650)
... 1 moreCaused by: javax.net.ssl.SSLProtocolException: SSL handshake
terminated: ssl=0xb91e9b40: Failure in SSL library, usually a protocol
errorerror:100c5416:SSL
routines:ssl3_read_bytes:SSLV3_ALERT_CERTIFICATE_UNKNOWN
(external/boringssl/src/ssl/s3_pkt.c:972 0xb9215530:0x00000001)at
com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native
Method)at
com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:353)
Interestingly if device-certificate is already active and we try to publish message through android it get published successfully. The only problem is to authenticate the certificate at first call. If my code is faulty it should not send message against activated-certificates.
The difference that I see between mosquitto call and the android-code is that mosquitto is making a single command to connect and publish the message, where as PAHO-MQTT in AWS SDK needs to connect first before publishing, and I get exception in 'connect'. I even did not get any logs in AWS logs.

Possible Reasons
SSL/TLS Handshake can fail for various reasons and not only for certificate validation problems.
It could be for:
Not sharing same cipher suites
Not sharing SSL versions
Certificate validation
Intent to change TLS version
Others issues
The best way to figure out what your problem is is to install Wireshark and see the handshake messages. Then based on the SSL alert message sent from server to client you can have more information on the SSL handshake failure, where specifically it happened.
Possible solution
Solution No. 1: This link might also help: Received fatal alert: handshake_failure through SSLHandshakeException
Solution No. 2: Could you try to upgrade the keystore for your Android App?
Helpful resources
https://serverfault.com/questions/639837/openssl-s-client-shows-alert-certificate-unknown-but-all-server-certificates-app#639866
https://aws.amazon.com/de/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/
https://aws.amazon.com/de/blogs/mobile/use-your-own-certificate-with-aws-iot/
https://stackoverflow.com/a/6353956/5157221

Make your own KeyStoreHelper that put CA Cert into your KeyStore, and use it instead of AWS IoT SDK's KeyStoreHelper.
Note: I omitted all exception handlings in the codes below, and createKeyPair(), createCSR(), parsePemObject() and signCSR() are my methods.
public class MyKeystoreHelper {
public KeyStore createKeystoreJIT(String certId, String keystorePath,
String keystoreName, String keystorePassword, HashMap<String, String> directory) {
// Generate KeyPair
KeyPair key = createKeyPair();
// Generate CSR
PKCS10CertificationRequest csr = createCSR(key, directory);
// Read CA Private key
PEMKeyPair pemKey = (PEMKeyPair)parsePemObject(context, PATH_TO_CAROOT_KEY_FILE);
KeyPair caKey = new JcaPEMKeyConverter().getKeyPair(pemKey);
// Read CA Cert
X509CertificateHolder pemCert = (X509CertificateHolder)parsePemObject(context, PATH_TO_CAROOT_CERT_FILE);
X509Certificate caCert = new JcaX509CertificateConverter().getCertificate(pemCert);
X500Name issuer = pemCert.getIssuer();
// Generate CA Signed CSR
X509Certificate cert = signCSR(csr, caKey.getPrivate(), caCert, issuer);
// Create Key Store
saveKeystore(certId, cert, caCert, key.getPrivate(), keystorePath, keystoreName, keystorePassword); // <-- HERE!! Pass CA Cert
KeyStore keystore = getKeystore(certId, keystorePath, keystoreName, keystorePassword);
return keystore;
}
....
private boolean saveKeystore(String certId, X509Certificate cert, X509Certificate caCert,
PrivateKey privatekey, String keystorePath, String keystoreName, String keystorePassword) {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
File keystoreFile = new File(keystorePath, keystoreName);
if( ! keystoreFile.exists()) {
createKeystore(keystorePath, keystoreName, keystorePassword);
}
FileInputStream fis = new FileInputStream(keystoreFile);
keystore.load(fis, keystorePassword.toCharArray());
fis.close();
keystore.setCertificateEntry(certId, cert);
keystore.setKeyEntry(certId, privatekey, keystorePassword.toCharArray(), new Certificate[] { cert, caCert }); // <-- HERE!! put CA Cert
String caCertId = certId + "_CA";
keystore.setCertificateEntry(caCertId, caCert);
keystore.setKeyEntry(caCertId, privatekey, keystorePassword.toCharArray(), new Certificate[] { caCert });
String keystoreFileAndPath;
if(keystorePath.endsWith("/")) {
keystoreFileAndPath = keystorePath + keystoreName;
} else {
keystoreFileAndPath = keystorePath + "/" + keystoreName;
}
FileOutputStream fos = new FileOutputStream(keystoreFileAndPath);
keystore.store(fos, keystorePassword.toCharArray());
fos.close();
return true;
}
....
private KeyStore getMemoryKeystore(KeyStore customerKeystore, String certId, String customerKeystorePassword) {
KeyStore memoryKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
memoryKeystore.load(null);
X509Certificate cert = (X509Certificate) customerKeystore.getCertificate(certId);
memoryKeystore.setCertificateEntry("cert-alias", cert);
Key key = customerKeystore.getKey(certId, customerKeystorePassword.toCharArray());
String caCertId = certId + "_CA";
X509Certificate caCert = (X509Certificate) customerKeystore.getCertificate(caCertId); // Pull CA Cert
memoryKeystore.setCertificateEntry("cacert-alias", caCert);
memoryKeystore.setKeyEntry("key-alias", key, AWS_IOT_INTERNAL_KEYSTORE_PASSWORD.toCharArray(), new Certificate[] { cert, caCert }); // <-- HERE!!
return memoryKeystore;
}
....
}
And before you connect and publish MQTT, get CSR and CA Cert that are chained within the KeyStore as below:
keystoreHelper = new MyKeystoreHelper(...);
if(keystoreHelper.isKeystorePresent(keystorePath, KEYSTORE_NAME)) {
keystore = keystoreHelper.getKeystore(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD);
} else {
// Create your own KeyStroe if it is not exist yet.
HashMap<String, String> directory = getDirectory(); // X.500 directory items for CSR
keystoreHelper.createKeystoreJIT(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD, directory);
keystore = keystoreHelper.getKeystore(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD);
}
Once you publish any message to the endpoint for the first time, AWS IoT Core will automatically create a "Thing".
I hope this helps you.

Related

image is not loading from url in glide on android kikat and lollipop [duplicate]

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());
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.
The solution of #Chrispix is dangerous! Trusting all certificates allows anybody to do a man in the middle attack! Just send ANY certificate to the client and it will accept it!
Add your certificate(s) to a custom trust manager like described in this post: Trusting all certificates using HttpClient over HTTPS
Although it is a bit more complex to establish a secure connection with a custom certificate, it will bring you the wanted ssl encryption security without the danger of man in the middle attack!
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;
}
}
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.
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 CA that issued the server certificate was unknown
The server certificate wasn't signed by a CA, but was self signed
The server configuration is missing an intermediate CA
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
Trying to access a remote api from your local machine.
You are building for Android app
Your remote server is under proxy filtration (you use proxy in your browser setting to access the remote api service, typically a staging or dev server)
You are testing on real device
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
Build > Clean Project, wait till it finish cleaning
Build > Generate Signed APK
Click Choose existing... button
Select the .keystore file we just created in the Create .keystore file section
Enter the same password you created while creating in Create .keystore file section. Use same password for Key store password and Key password fields. Also enter the alias
Click Next button
In the next screen; which might be different based on your settings in build.gradle files, you need to select Build Types and Flavors.
For the Build Types choose release from the dropdown
For 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:
Click the Setting inside Android phone and then wi-fi
Long press on the connected wifi and select Modify network
Click the Advanced options if you can't see the Proxy Hostname field
In the Proxy Hostname enter the host IP or name you want to connect. A typical staging server will be named as stg.api.mygoodcompany.com
For the port enter the four digit port number for example 9502
Hit the Save button
One Last Stop:
Remember we generated the signed apk file in Sign APK File section. Now is the time to install that APK file.
Open a terminal and changed to the signed apk file folder
Connect your Android device to your machine
Remove any previous installed apk file from the Android device
Run adb install name of the apk file
If for some reason the above command return with 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!
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'
UPDATE
I also got another error on API 16 emulator:
routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
(external/openssl/ssl/s23_clnt.c:741'.
Reading 1 and 2, I changed code so:
okHttpClient = getOkHttpBuilder().build()
private fun getOkHttpBuilder(): OkHttpClient.Builder {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Security.insertProviderAt(Conscrypt.newProvider(), 1)
}
return OkHttpClient().newBuilder()
}
// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'
I also removed these lines from MyApplication:
try {
ProviderInstaller.installIfNeeded(applicationContext)
val sslContext = SSLContext.getInstance("TLSv1.2")
sslContext.init(null, null, null)
sslContext.createSSLEngine()
} catch (e: GooglePlayServicesRepairableException) {
Timber.e(e.stackTraceToString())
// Prompt the user to install/update/enable Google Play services.
GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
} catch (e: GooglePlayServicesNotAvailableException) {
Timber.e(e.stackTraceToString())
// Prompt the user to install/update/enable Google Play services.
// GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
} catch (e: NoSuchAlgorithmException) {
Timber.e(e.stackTraceToString())
} catch (e: KeyManagementException) {
Timber.e(e.stackTraceToString())
}
But the library adds 3.4 Mb to apk.
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.
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.
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 my case, the root & intermediate certificates was successfully installed but I still got "Trust anchor for certification path not found." exception!. After digging the android document, found out that by default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default. If your app running on a OS with api level higher than 23 you should explicitly allow the app to trust user-added CA by adding its address to network_security_config like bellow:
<domain-config>
<domain includeSubdomains="true">PUT_YOUR_SERVER_ADDERESS</domain>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</domain-config>
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).
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.
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.
https://stackoverflow.com/a/60102517/114265
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.
Sometimes it happens when admins setup the certificate incorrectly
Check URL here
https://www.sslshopper.com/ssl-checker.html
In my case, there was an error
The certificate is not trusted in all web browsers. You may need to install an Intermediate/chain certificate to link it to a trusted root certificate. Learn more about this error. You can fix this by following GlobalSign's Certificate Installation Instructions for your server platform. Pay attention to the parts about Intermediate certificates.
I use these methods that one of them is in solutions above works for me :
First:
public okhttp3.OkHttpClient 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();
okhttp3.OkHttpClient.Builder builder = new
okhttp3.OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory,
(X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession
session) {
return true;
}
});
okhttp3.OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Second:
#SuppressLint("TrulyRandom")
public static void handleSSLHandshake() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{new
X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
#Override
public void checkClientTrusted(X509Certificate[]
certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[]
certs, String authType) {
}
}};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new
HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception ignored) {
}
}
and:
put this libraries to your classpath:
implementation 'com.squareup.okhttp:okhttp:2.3.0'
implementation 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-
core:3.3.0'
be sure that you call them in your class
In my case, the certificate in the website was correct (Issuer = GlobalSign RSA OV SSL CA 2018), but the certificate file I was downloading was wrong, because of the Antivirus that was "intercepting" the certificate and deliverying a new different certificate to download fron the browsers (Issuer = ESET SSL Filter CA) !!!
Check your certificate file has the correct issuer.
**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);
Relpcae your clicent Like below
var httpClient = new HttpClient(new System.Net.Http.HttpClientHandler());
Change https to http

Android Marshmallow view user certificates and associate cert with private key

I've created a key pair, stored the private key in the AndroidKeystore.
Generated a CSR using the Public key from the key pair
Exported the CSR to the CA, and got it to generate a cert
Installed the cert on the phone
Now, I'm trying to associate the private key from #1 with the cert that was installed at step #4.
Have looked all day, cannot find a mechanism to do it. Android documentation suggests using the KeyStore.setKeyEntry method. I intend to use it but am unable to read the cert that was installed.
I can display all certs in the AndroidCAStore, and I do see this newly installed cert in the "User certificates" section on the phone but am unable to read it programatically. Any ideas ?
Trying to do pretty much the same thing. The key association with the signed cert also works using keystore.setEntry. What I can't get to work is this user cert then to appear in the "IPSec User certificate" listbox when trying to add a VPN. Running on Marshmallow 6.0.1
My logic looks like this
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyGen = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
keyGen.initialize(
new KeyGenParameterSpec.Builder(
"myAlias",
KeyProperties.PURPOSE_SIGN)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp384r1"))
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA384,
KeyProperties.DIGEST_SHA512)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setUserAuthenticationRequired(false)
.setKeyValidityStart(now)
.setKeyValidityForOriginationEnd(nowPlusThreeYears)
.build());
keyPair = keyGen.generateKeyPair();
privateKey = (PrivateKey) keyStore.getKey("myAlias", null);
publicKey = keyStore.getCertificate("myAlias").getPublicKey();
Certificate[] chain = keyStore.getCertificateChain("myAlias");
keyStore.setKeyEntry("myAlias", privateKey, null, chain);
StringBuilder x500PrincipalBuilder = new StringBuilder("CN=");
x500PrincipalBuilder.append("My Company");
x500PrincipalBuilder.append(", ");
x500PrincipalBuilder.append("L=");
x500PrincipalBuilder.append("My Location");
x500PrincipalBuilder.append(", ");
x500PrincipalBuilder.append("ST=");
x500PrincipalBuilder.append("CA");
x500PrincipalBuilder.append(", ");
x500PrincipalBuilder.append("O=");
x500PrincipalBuilder.append("My Org");
x500PrincipalBuilder.append(", ");
x500PrincipalBuilder.append("OU=");
x500PrincipalBuilder.append("my ou");
x500PrincipalBuilder.append(", ");
x500PrincipalBuilder.append("C=");
x500PrincipalBuilder.append("US");
Signature ecdsaSignature = Signature.getInstance("SHA384withECDSA");
ecdsaSignature.initSign(keyPair.getPrivate());
byte[] strByte = new byte[0];
strByte = x500PrincipalBuilder.toString().getBytes(UTF8_CHARSET);
ecdsaSignature.update(strByte);
X500Principal x500Principal = new X500Principal(x500PrincipalBuilder.toString());
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
x500Principal, keyPair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(signatureGenerator.getSigningAlgorithm());
ContentSigner signer = csBuilder.build(keyPair.getPrivate());
org.bouncycastle.pkcs.PKCS10CertificationRequest csr = p10Builder.build(signer);
PemObject pemObject = new PemObject("CERTIFICATE REQUEST", csr.getEncoded());
StringWriter str = new StringWriter();
PEMWriter pemWriter = new PEMWriter(str);
pemWriter.writeObject(pemObject);
pemWriter.close();
str.close();
// write the csr to a file
// get it signed by the CA (Microsoft CA)
// Push the cert to the phone
// Install the cert
Certificate clientCertSignedByCA = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream("/path/to/cert.cer));
KeyStore.Entry entry = keyStore.getEntry("myAlias", null);
PrivateKey privateKey = (PrivateKey) keyStore.getKey("myAlias", null);
Certificate[] chain = new Certificate[1];
chain[0] = clientCertSignedByCA;
keyStore.setKeyEntry("myAlias", privateKey, null, chain);

No peer certificate Exception - Volley and Android with self signed certificate

I'm trying to make my app communicate with my server via https.
As I don't want to pay to get my server certificate signed by a trusted CA, the solution is to use a self signed certificate.
So, I've created my caconfig.cnf as follows:
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = ./demoCA # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir
certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
private_key = $dir/private/cakey.pem # CA private key
RANDFILE = $dir/private/.rand # random number file
default_days = 365 # how long to certify for
default_crl_days = 30 # how long before next CRL
default_md = md5 # md to use
policy = policy_any # default policy
email_in_dn = no # Don't add the email into cert DN
name_opt = ca_default # Subject name display option
cert_opt = ca_default # Certificate display option
copy_extensions = none # Don't copy extensions from request
[ policy_any ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Then, I've created and signed my certificate using the following commands:
$ mkdir myCA myCA/private myCA/newcerts
$ echo "01" > myCA/serial
$ touch demoCA/index.txt
$ openssl genrsa -des3 -out myCA/private/cakey.pem 1024
$ openssl req -new -x509 -days 3650 -key myCA/private/cakey.pem -out myCA/cacert.pem
$ openssl req -sha1 -newkey rsa:2048 -keyout server-key.pem -out server-cert-req.pem -subj '/CN=myhost/' -nodes
$ openssl ca -config caconfig.cnf -in server-cert-req.pem -out server-cert.pem
$ openssl x509 -inform PEM -in cacert.pem -outform DER -out certificate.cer
$ rm server-cert-req.pem
In my nodejs server code, I'm creating the https server like this:
var express = require('express');
var https = require('https');
var PORT = 443;
var app = express();
app.get('/', function (req, res) {
res.send("Server is working");
});
var httpsOptions = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem')
};
https.createServer(httpsOptions, app).listen(PORT, function() {
console.log('%s: Node server started on port %d ...', Date(Date.now() ), PORT);
});
In order to test if everything is correct, I've also created a node client script, which makes a request to my server. Here is the code for my node client:
var https = require('https');
var fs = require('fs');
var request = https.request({
host: 'myhost',
port: 443,
path: '/',
method: 'GET',
rejectUnauthorized: true,
// Once it is self signed, I'm using my server certificate (public key).
ca: [fs.readFileSync('cacert.pem').toString()]
}, function(response) {
response.on('data', function(data) {
console.log(data.toString());
});
});
request.on('error', function(err) {
console.log(err);
})
request.end();
When I run my node client script, it works perfectly. On the other hand, the Android Volley Examples app, which I'm using to check how Volley works with https, is not working. Below, I'm describing all the steps I've followed in order to try to make it work.
I've created a .bks file using my certificate.cer file using the following command:
keytool -importcert -v -trustcacerts -file "certificate.cer" -alias IntermediateCA -keystore "res/raw/my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret
Then, I've verified if the certificate was imported correctly into the .bks as follows:
keytool -list -keystore "res/raw/my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret
And I got the following output, that means it's correct:
Keystore type: BKS
Keystore provider: BC
Your keystore contains 1 entry
imeto_alias, Oct 16, 2014, trustedCertEntry,
Certificate fingerprint (SHA1): 03:DC:A1:6A:9B:1D:AD:59:A9:9B:1F:C2:43:7E:80:07:3B:B6:BE:CB
I've came across to this tutorial, and, as I'm using Volley, I've decided to follow it. So, below are the following changes I've made to the example project.
Got Volley from git clone https://android.googlesource.com/platform/frameworks/volley
Got Android Volley Examples project from git clone git://github.com/ogrebgr/android_volley_examples.git
Copied my_keystore.bks containing the self-signed public key in res/raw;
Opened Act_SsSslHttpClient in the examples project, found "R.raw.test" and replaced it with R.raw.my_keystore;
Found "new SslHttpClient(" and replaced the default password "test123″ with "mysecret";
Replaced "44400" with the HTTPS port of my server/virtualhost ("443"). (I could also remove this parameter since "443" is the default port;
Replaced "https://tp.bolyartech.com:44400/https_test.html" with my server URL.
Started the app, went to "HTTPS with self-signed cert", then "Execute HTTPS request"
But, when I pressed the button, I got the following exception:
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Below, is my JavaCode...
public class Act_SsSslHttpClient extends Activity {
private TextView mTvResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act__ss_ssl_http_client);
mTvResult = (TextView) findViewById(R.id.tv_result);
Button btnSimpleRequest = (Button) findViewById(R.id.btn_simple_request);
btnSimpleRequest.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Replace R.raw.test with your keystore
InputStream keyStore = getResources().openRawResource(R.raw.my_keystore);
// Usually getting the request queue shall be in singleton like in {#seeAct_SimpleRequest}
// Current approach is used just for brevity
RequestQueue queue = Volley.newRequestQueue(Act_SsSslHttpClient.this,
new ExtHttpClientStack(new SslHttpClient(keyStore,
"mysecret")));
StringRequest myReq = new StringRequest(Method.GET,
"https://myServerURL/",
createMyReqSuccessListener(),
createMyReqErrorListener());
queue.add(myReq);
}
});
}
...
}
Does anybody know the solution?
Thank you.
I am using self signed certificate in my test environment. To make it work I call this method in my Application class in onCreate method. It makes all certificates accepted. It is not save, but for test purposes is ok.
#Override
public void onCreate() {
nuke();
super.onCreate();
}
public static void nuke() {
try {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}
#Override
public void checkClientTrusted(X509Certificate[] certs,
String authType) {}
#Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) {}
} };
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {}
}

Creating an Https connecion with Client Side Certificate from PKCS#10 with SpongyCastle

The goal
I'm working on implementing communication with Client-Certificate.
Step 1: Create a PKCS#10 request (CSR) and give it to the my server for signing. The server contacts passes the CSR to the CA, and the CA signs it, and returns a PKCS#7 (with the signed PKCS#10 and the CA's certificate).
Step 2: Create a PKCS#12, store it securely on the Android device
Step 3: Create SSL connection so that the client will be authenticated according to the certificate.
Now, Step 1 works perfectly using SpongyCastle 1.50.0.0, but I'm stuck on the other steps...
I'm currently getting an SSL-Handshake exception, but I got the feeling that I should re-think on my implementation.
The question
Does anyone know how to implement the flow? How to create and store whatever's needed for a client side certificate to work well with Android's SSLContext, and how to create such SSLContext?
What I tried so far
My first attempt was to use the KeyChain, but we'd like to avoid the user interaction as described there. My second attempt was to follow Rich Freedman's steps, but I don't know how to create a PKCS#12 from the PKCS#7 and the private key. For persistence, I went over this post, but (a) it's C#, (b) it's unencrypted and (c) I think that the android platform has a better keys persistence mechanism, one that I yet know nothing about. Lastly, this code (for creating a PKCS12 from PEM and PKCS#7) didn't work as well, as I didn't know how to get a CER file and the rest of the things it needs.
Thanks!
Maybe not the best code, but it works, it does not strictly answer all you questions but maybe you will find pieces you can use.
Your flow is good, I'm doing the almost the same thing.
I'm keeping my keys in dynamically created keystore. Additionaly i have keystore with trusted certificates created with openssl tool.
For communication I've used okHttp + retrofit
https://github.com/square/okhttp
https://github.com/square/retrofit
Generate KeyPair:
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.genKeyPair();
return keyPair;
}
Generate csr:
private static PKCS10CertificationRequest generateCSRFile(KeyPair keyPair) throws IOException, OperatorCreationException {
String principal = "CN=company1, OU=company1, O=company1, C=GB";
AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded());
AlgorithmIdentifier signatureAlgorithm = new DefaultSignatureAlgorithmIdentifierFinder()
.find("SHA1WITHRSA");
AlgorithmIdentifier digestAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find("SHA-1");
ContentSigner signer = new BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm).build(privateKey);
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name(
principal), keyPair.getPublic());
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(true));
extensionsGenerator.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign
| KeyUsage.cRLSign));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extensionsGenerator.generate());
PKCS10CertificationRequest csr = csrBuilder.build(signer);
return csr;
}
Send csr (you may need to convert it to pem format), receive certificate .
Init keystore:
KeyStore store = KeyStore.getInstance("BKS");
InputStream in;
try {
in = App.getInstance().getApplicationContext().openFileInput(filename);
try {
store.load(in, password);
} finally {
in.close();
}
} catch (FileNotFoundException e) {
//create new keystore
store.load(null, password);
}
Init truststore:
KeyStore trustStore = KeyStore.getInstance("BKS");
InputStream in = App.getInstance().getApplicationContext().getResources().openRawResource(R.raw.truststore);
try {
trustStore.load(in, trustorePassword);
} finally {
in.close();
}
Add key to keystore (make sure your private key, and certificate match, keystore won't throw exception if they don't, and with okHttp this can cause libssl crashes (only on devices with api below 4.1):
keyStore.setKeyEntry(alias, privateKey, password, new X509Certificate[]{certificate});
Create okHttpClient with its own SSLContext:
OkHttpClient client = new OkHttpClient();
KeyStore keyStore = App.getInstance().getKeyStoreUtil().getKeyStore();
KeyStore trustStore = App.getInstance().getKeyStoreUtil().getTrustStore();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword);
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
client.setSslSocketFactory(sslCtx.getSocketFactory());
client.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
Look at Nikolay Elenkov blog, you can find many usefull informations with source code as well.
http://nelenkov.blogspot.com/
http://nelenkov.blogspot.com/2011/11/using-ics-keychain-api.html
http://nelenkov.blogspot.in/2011/12/ics-trust-store-implementation.html
http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html
http://nelenkov.blogspot.com/2013/08/credential-storage-enhancements-android-43.html
#edit
Post your exception
#edit2
In your case you need to extract your X509Certificate from webservice response, store it in keystore with privatekey used for generating csr request and store CA cert in another keystore which will work as truststore. (It can be the same keystore, but it's not recommended).

Trust Anchor not found for Android SSL Connection

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());
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.
The solution of #Chrispix is dangerous! Trusting all certificates allows anybody to do a man in the middle attack! Just send ANY certificate to the client and it will accept it!
Add your certificate(s) to a custom trust manager like described in this post: Trusting all certificates using HttpClient over HTTPS
Although it is a bit more complex to establish a secure connection with a custom certificate, it will bring you the wanted ssl encryption security without the danger of man in the middle attack!
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;
}
}
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.
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 CA that issued the server certificate was unknown
The server certificate wasn't signed by a CA, but was self signed
The server configuration is missing an intermediate CA
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
Trying to access a remote api from your local machine.
You are building for Android app
Your remote server is under proxy filtration (you use proxy in your browser setting to access the remote api service, typically a staging or dev server)
You are testing on real device
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
Build > Clean Project, wait till it finish cleaning
Build > Generate Signed APK
Click Choose existing... button
Select the .keystore file we just created in the Create .keystore file section
Enter the same password you created while creating in Create .keystore file section. Use same password for Key store password and Key password fields. Also enter the alias
Click Next button
In the next screen; which might be different based on your settings in build.gradle files, you need to select Build Types and Flavors.
For the Build Types choose release from the dropdown
For 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:
Click the Setting inside Android phone and then wi-fi
Long press on the connected wifi and select Modify network
Click the Advanced options if you can't see the Proxy Hostname field
In the Proxy Hostname enter the host IP or name you want to connect. A typical staging server will be named as stg.api.mygoodcompany.com
For the port enter the four digit port number for example 9502
Hit the Save button
One Last Stop:
Remember we generated the signed apk file in Sign APK File section. Now is the time to install that APK file.
Open a terminal and changed to the signed apk file folder
Connect your Android device to your machine
Remove any previous installed apk file from the Android device
Run adb install name of the apk file
If for some reason the above command return with 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!
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'
UPDATE
I also got another error on API 16 emulator:
routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
(external/openssl/ssl/s23_clnt.c:741'.
Reading 1 and 2, I changed code so:
okHttpClient = getOkHttpBuilder().build()
private fun getOkHttpBuilder(): OkHttpClient.Builder {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Security.insertProviderAt(Conscrypt.newProvider(), 1)
}
return OkHttpClient().newBuilder()
}
// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'
I also removed these lines from MyApplication:
try {
ProviderInstaller.installIfNeeded(applicationContext)
val sslContext = SSLContext.getInstance("TLSv1.2")
sslContext.init(null, null, null)
sslContext.createSSLEngine()
} catch (e: GooglePlayServicesRepairableException) {
Timber.e(e.stackTraceToString())
// Prompt the user to install/update/enable Google Play services.
GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
} catch (e: GooglePlayServicesNotAvailableException) {
Timber.e(e.stackTraceToString())
// Prompt the user to install/update/enable Google Play services.
// GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
} catch (e: NoSuchAlgorithmException) {
Timber.e(e.stackTraceToString())
} catch (e: KeyManagementException) {
Timber.e(e.stackTraceToString())
}
But the library adds 3.4 Mb to apk.
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.
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.
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 my case, the root & intermediate certificates was successfully installed but I still got "Trust anchor for certification path not found." exception!. After digging the android document, found out that by default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default. If your app running on a OS with api level higher than 23 you should explicitly allow the app to trust user-added CA by adding its address to network_security_config like bellow:
<domain-config>
<domain includeSubdomains="true">PUT_YOUR_SERVER_ADDERESS</domain>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</domain-config>
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).
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.
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.
https://stackoverflow.com/a/60102517/114265
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.
Sometimes it happens when admins setup the certificate incorrectly
Check URL here
https://www.sslshopper.com/ssl-checker.html
In my case, there was an error
The certificate is not trusted in all web browsers. You may need to install an Intermediate/chain certificate to link it to a trusted root certificate. Learn more about this error. You can fix this by following GlobalSign's Certificate Installation Instructions for your server platform. Pay attention to the parts about Intermediate certificates.
I use these methods that one of them is in solutions above works for me :
First:
public okhttp3.OkHttpClient 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();
okhttp3.OkHttpClient.Builder builder = new
okhttp3.OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory,
(X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession
session) {
return true;
}
});
okhttp3.OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Second:
#SuppressLint("TrulyRandom")
public static void handleSSLHandshake() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{new
X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
#Override
public void checkClientTrusted(X509Certificate[]
certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[]
certs, String authType) {
}
}};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new
HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception ignored) {
}
}
and:
put this libraries to your classpath:
implementation 'com.squareup.okhttp:okhttp:2.3.0'
implementation 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-
core:3.3.0'
be sure that you call them in your class
In my case, the certificate in the website was correct (Issuer = GlobalSign RSA OV SSL CA 2018), but the certificate file I was downloading was wrong, because of the Antivirus that was "intercepting" the certificate and deliverying a new different certificate to download fron the browsers (Issuer = ESET SSL Filter CA) !!!
Check your certificate file has the correct issuer.
**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);
Relpcae your clicent Like below
var httpClient = new HttpClient(new System.Net.Http.HttpClientHandler());
Change https to http

Categories

Resources