I tried to look for some answers for me here, but I just fail to find anything that solves my problem.
In project I am working on we are going to change our domain. Change is bit tricky - we have to also change connection from HTTP to HTTPS. I've received .crt key (let's say, example.tech.crt - will change all of company name to "example"). After few hours of constant failures I decided to write here.
First of all, I tried using this tutorial http://ogrelab.ikratko.com/using-android-volley-with-self-signed-certificate/ - and it didn't work (I don't even mean that I had to use deprecated Apache libs because of API23). In case this is needed, this is how I created BKS file:
keytool -importcert -v -trustcacerts -file "example.tech.crt" -alias example_tech
-keystore "example_tech.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider
-providerpath "bcprov-jdk16-146.jar" -storetype BKS
Then, I tried this approach Does Android Volley support SSL? - the one from best answer (with ignoring domain name check). I still tried to use BKS file - I've got some exceptions about casting errors, so I changed line:
CertificateFactory cf = CertificateFactory.getInstance("X.509");
to
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
as suggested somewhere - error still persisted. I tried to use .crt file instead of BKS - I still fail.
Every single time I get same error:
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException:
SSL handshake aborted: ssl=0x650f83a0: Failure in SSL library, usually a protocol error
error:14077102:SSL routines:SSL23_GET_SERVER_HELLO:unsupported protocol
(external/openssl/ssl/s23_clnt.c:714 0x5fda0d74:0x00000000)
I tried to do pretty much same requests using Postman and they work on same address without any problem, so this is not server problem. I tried to use various domains - example.tech, www.example.tech, example.tech:80 and so on (always with https of course).
Below is example curl-like request (of course censored):
curl request: curl -X "POST"
-D "grant_type=password&password=[passwordHere]&username=[emailHere]&"
-H 'Authorization: Basic [tokenHere]
"https://example.tech/oauth/token"
I fail to see what's wrong with my code and I'd be really happy to see what I am doing wrong in here. If there's any more code needed, feel free to ask for it (but 99% of it is like in second link, only with really small changes).
Consider this topic as example of poor comunication. After hours of trying to make this work we made to work:
we are NOT using selfsigned certificates, so adding key to application is terrible idea (since they change each 3 months)
unsupported protocol exception came from older Android APIs (<20 or <21), which are supported in this application. From I do understand (considering my poor knowledge about SSL connections) our site uses TLS, but older Android systems (pre-Lollipop I guess) have this turned off by default. Proper way of fixing this was creating custom TLSSocketFactory and using it in HurlStack used to initialize RequestQueue. After that exception disappeared.
Related
I'm using Robolectric 4.3.1 (testImplementation "org.robolectric:robolectric:4.3.1") to create an Android sqlite environment for my integration tests. My system uses OkHttp (implementation 'com.squareup.okhttp3:okhttp:3.14.7') for real HTTP requests. I'm not using MockWebServer.
After I upgraded to the Android 10 SDK, I had to update my unit test JVM to JDK 9, per the Robolectric instructions:
Running tests on Android API 29 now strictly requires a Java9 runtime or newer. If you are seeing errors about unsupported Java version when running tests on API 29 via Android Studio; you can use the 'JRE' field in the Run Configuration dialog to configure a newer Java runtime. See https://developer.android.com/studio/run/rundebugconfig for more background.
However, now my integration tests fail with:
java.lang.NullPointerException: No password supplied for PKCS#12 KeyStore.
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
at java.base/java.security.KeyStore.load(KeyStore.java:1479)
at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:367)
at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:315)
at java.base/sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:59)
at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:51)
at java.base/javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:278)
at okhttp3.internal.Util.platformTrustManager(Util.java:640)
at okhttp3.OkHttpClient.<init>(OkHttpClient.java:228)
at okhttp3.OkHttpClient.<init>(OkHttpClient.java:202)
How can I make real HTTP calls again?
TLDR
to workaround this problem, set the javax.net.ssl.trustStoreType system property to JKS:
-Djavax.net.ssl.trustStoreType=JKS
Details
I found this workaround:
After trying many things I finally found one workaround:
System.setProperty("javax.net.ssl.trustStore", "NONE")
MockWebServer()
The tests are passing with this additional configuration.
However, when I tried that workaround, all of my HTTP calls failed with the following ConnectException instead:
java.net.ConnectException: Failed to connect to myhost.com:443
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:265)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:183)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
at okhttp3.RealCall.execute(RealCall.java:81)
I suspect that OkHttp rightly denies all TLS connections because it doesn't trust them since the workaround suggests setting the javax.net.ssl.trustStore to NONE.
I also tried specifying the default password for java truststores, changeit via this workaround:
Workaround: -Djavax.net.ssl.trustStorePassword=changeit
But then I got the following exception when trying to instantiate an OkHttpClient:
java.lang.AssertionError: No System TLS
at okhttp3.internal.Util.platformTrustManager(Util.java:648)
at okhttp3.OkHttpClient.<init>(OkHttpClient.java:228)
at okhttp3.OkHttpClient.<init>(OkHttpClient.java:202)
which was caused by:
Caused by: java.security.KeyStoreException: problem accessing trust store
at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:75)
at java.base/javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:278)
at okhttp3.internal.Util.platformTrustManager(Util.java:640)
... 22 more
Caused by: java.io.IOException: stream does not represent a PKCS12 key store
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
at java.base/java.security.KeyStore.load(KeyStore.java:1479)
at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:367)
at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:315)
at java.base/sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:59)
at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:51)
... 24 more
This was a great clue. I started debugging the JDK 9 source with Android Studio, and I noticed that when I ran with org.junit.runners.BlockJUnit4ClassRunner, my KeyStore.keystoreSpi was a sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12, but when I ran with org.robolectric.RobolectricTestRunner my KeyStore.keystoreSpi was a org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi$BCPKCS12KeyStore.
According to JEP-229:
This feature changes the default keystore type from JKS to PKCS12. By default, new keystores will be created in the PKCS12 keystore format. Existing keystores will not change and keystore applications can continue to explicitly specify the keystore type they require.
Existing applications must not be disrupted. Keystores tend to be long-lived, so we need to support access across several JDK releases. Applications that access keystores created by earlier JDK releases must run unaltered on JDK 9. Similarly, applications that access keystores created by JDK 9 should run unaltered on earlier JDK releases.
This requirement is achieved by introducing a keystore detection mechanism that understands both the JKS and PKCS12 formats. A keystore's format is examined before it is loaded to determine its type and then the appropriate keystore implementation is used to access it. The mechanism is enabled by default but can be disabled if required.
Support for this keystore-detection mechanism may be backported to earlier JDK releases.
Thus, the classic $JAVA_HOME/lib/security/cacerts is still a Java Key Store, which I could verify:
$ file /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/lib/security/cacerts
/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/lib/security/cacerts: Java KeyStore
However, since the JDK wants to default to PKCS12 keystores, the JDK's DualFormatPKCS12 will fall back to a JKS if reading a file as PKCS12 fails. Bouncycastle assumes that when the javax.net.ssl.trustStoreType is pkcs12 that is really what we mean.
Thus, to workaround this problem, set the javax.net.ssl.trustStoreType system property to JKS:
-Djavax.net.ssl.trustStoreType=JKS
I filed issues with bouncycastle and robolectric about this.
If you're facing this issue with Robolectric, upgrade the version to 4.4 as these has been resolved in version 4.4
testImplementation ('org.robolectric:robolectric:4.4')
We are facing some issues in connecting to Google’s GCM API (https://android.googleapis.com/gcm/send ) for Android push notifications from our server (SSLHandshakeException).
From 28th February to 8th March 2018 the issue was intermittent(push sent sometimes, SSL handshake error otherwise). From 9th March 2018 the issue is continuous.
Please see the logs below. Would like to know if there was any changes to the issued certificates.
com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:151)
I do not fully understand the details, but when I update our push provider/server "External Services Certs" and add the cert below.. my push started working again. So even though the Equifax cert that I originally installed 2 years ago was working until a few weeks ago, something changed on the GCM server and that cert was no longer valid. It has an expiration date of Aug 2018, which is near, but should not expire till that date.
I did notice that the new cert is SHA256 and the original is SHA1, so maybe this is a required security upgrade. It kind of screws me since my push content providers are distributed, not in a single location where it is easy to update the cert :(
The cert that fixed my issue is:
-----BEGIN CERTIFICATE-----
MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAw
HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs
U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy
MTUwMDAwNDJaMFQxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg
U2VydmljZXMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzMw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKUkvqHv/OJGuo2nIYaNVW
XQ5IWi01CXZaz6TIHLGp/lOJ+600/4hbn7vn6AAB3DVzdQOts7G5pH0rJnnOFUAK
71G4nzKMfHCGUksW/mona+Y2emJQ2N+aicwJKetPKRSIgAuPOB6Aahh8Hb2XO3h9
RUk2T0HNouB2VzxoMXlkyW7XUR5mw6JkLHnA52XDVoRTWkNty5oCINLvGmnRsJ1z
ouAqYGVQMc/7sy+/EYhALrVJEA8KbtyX+r8snwU5C1hUrwaW6MWOARa8qBpNQcWT
kaIeoYvy/sGIJEmjR0vFEwHdp1cSaWIr6/4g72n7OqXwfinu7ZYW97EfoOSQJeAz
AgMBAAGjggEzMIIBLzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH
AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHfCuFCa
Z3Z2sS3ChtCDoH6mfrpLMB8GA1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYu
MDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdv
b2cvZ3NyMjAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dz
cjIvZ3NyMi5jcmwwPwYDVR0gBDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYc
aHR0cHM6Ly9wa2kuZ29vZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA
HLeJluRT7bvs26gyAZ8so81trUISd7O45skDUmAge1cnxhG1P2cNmSxbWsoiCt2e
ux9LSD+PAj2LIYRFHW31/6xoic1k4tbWXkDCjir37xTTNqRAMPUyFRWSdvt+nlPq
wnb8Oa2I/maSJukcxDjNSfpDh/Bd1lZNgdd/8cLdsE3+wypufJ9uXO1iQpnh9zbu
FIwsIONGl1p3A8CgxkqI/UAih3JaGOqcpcdaCIzkBaR9uYQ1X4k2Vg5APRLouzVy
7a8IVk6wuy6pm+T7HT4LY8ibS5FEZlfAFLSW8NwsVz9SBK2Vqn1N0PIMn5xA6NZV
c7o835DLAFshEWfC7TIe3g==
-----END CERTIFICATE-----
I obtained it by running this openssl cmd and it is the second one in the chain. That CAfile parm is robably not needed, since I did not have that file and there was a complaint, but the required cert chain was still displayed.
openssl s_client -connect gcm-http.googleapis.com:443/gcm/send -debug -showcerts -CAfile entrust_2048_ca.cer
The issue was due to GeoTrust to GoogleTrust migration of the SSL certificates for googleapis.com. Issue got fixed when we imported new certificate from the URL: https://android.googleapis.com and added to our server's trust store.
Kari - that is what I figured. Thanks for replying.. but the URL you list gives 404.. can you double check and update if you have the correct URL.
I am seeing the same issue and the same SSL error. Any more discussion on this?
I have followed the steps as mentioned in below url :
Configuring SSL between MobileFirst adapters & back-end servers by using self-signed certificates.
After performing above steps, I am able to see the certificate in key store with correct alias name 'mydomain.com'. However, when I try to invoke the procedure which has defined in HTTP adapter to make a call to back end server using HTTPS, below exception has thrown in worklight server console.
FWLSE0152E: Unable to find certificate chain with alias: 'mydomain.com'
Could you please provide any suggestions which would help us to resolve this issue.
Looks like the CN of your backend server is not equals to backend domain name that you defined in the adapter xml file.
If the CN=mydomain.com try to export public certificate from backend keystore and import it into adapter's keystore using open ssl library.
I get the following error when I to use my keystore :
$ keytool -list -keystore instavert.keystore
keytool error : java.security.cert.CertificateParsingException: java.io.IOException: Parse Generalized time, invalid format
I searched on Google and SO, but none of the solution worked...
Did anyone ever experienced the same issue?
You get this exception when you specified too big value for validity. Keytool does not do a great job on input validation when creating the keys and then it is not able to read the generated keystore. It is better to keep a backup from the keystore.
I use OpenSSL to establish a secured connection with my local HTTPS server. The server is really simple as I basically used the Boost Asio example but only improved a bit.
The solution works on Win7 64b using OpenSSL-Win32 and the certificates which comes with installer downloaded here.
I have ported the solution on Android. The Android OpenSSL port is from here.
Everything works fine until the use_tmp_dh_file method is called:
_context.use_tmp_dh_file("/sdcard/Download/PEM/dh512.pem");
It always ends up with the Fatal signal 11 (SIGSEGV) at 0x00000014 (code=1) error.
I use certificates server.pem and dh512.pem from the /apps folder of Android OpenSSL port.
Does anybody have an idea what is wrong?
EDIT:
Using a dh file is not mandatory, it works without it, but I am only a one step further because now it fails when starting handshake:
boost::system::error_code error;
socket.handshake(boost::asio::ssl::stream_base::server, error);
Where socket is instance of:
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslSocket;
It ends up with the same error as above. It seems to be an Android OpenSSL-Boost ASIO issue.
The answer on this particular question is short and simple, but it was quite hard to find it. The native library implementing my HTTPS server was interfering with the other native library using OpenSSL as well.