Background
SSLv3 protocol is insecure,after i read some articles, i use this solution to remove this protocol.
The method remove sslv3:
#Override
public void setEnabledProtocols(String[] protocols) {
if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
// no way jose
// see issue https://code.google.com/p/android/issues/detail?id=78187
List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
for (String pro : enabledProtocols) {
VolleyLog.d(pro);
}
if (enabledProtocols.size() > 1) {
enabledProtocols.remove("SSLv3");
VolleyLog.d("Removed SSLv3 from enabled protocols");
} else {
VolleyLog.d("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
}
protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
}
super.setEnabledProtocols(protocols);
}
I use Volley as http client, here is my code to initialize a requestqueue:
HttpStack stack;
if (Build.VERSION.SDK_INT >= 9) {
// Use a socket factory that removes sslv3
// https://code.google.com/p/android/issues/detail?id=78187
stack = new HurlStack(null, new NoSSLv3Compat.NoSSLv3Factory());
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
Device and Environment
I am using Xiaomi M3 with MIUI ROM, which is based on Android 4.4.4.
When the setEnabledProtocols method is called, i print some log:
D/Volley: [1444] NoSSLv3SSLSocket.setEnabledProtocols: SSLv3
D/Volley: [1444] NoSSLv3SSLSocket.setEnabledProtocols: TLSv1
D/Volley: [1444] NoSSLv3SSLSocket.setEnabledProtocols: Removed SSLv3 from enabled protocols
Problem
When i try to load this image, failed, output:
NoConnectionError: javax.net.ssl.SSLHandshakeException:
javax.net.ssl.SSLProtocolException: SSL handshake terminated:
ssl=0x77f49768: Failure in SSL library, usually a protocol error
E/CachedHttp: error:1409443E:SSL routines:SSL3_READ_BYTES:tlsv1 alert
inappropriate fallback (external/openssl/ssl/s3_pkt.c:1256
0x77f4c280:0x00000003)
this image server supports the following protocols:
TLS 1.2、 TLS 1.1、 TLS 1.0、 SSL 3
Could you please help me to figure it out?
Did you check the size of keys. Enable debug log to see the exact issue. Probably is being caused by insufficient key size by the backend you are trying to connect to.
Enable JCE Unlimited for java 7
Identify handshake errors
Related
I am trying to test ssl mutual certification of android webview.
I setup an environment as below and tested via PC web browser, everything is OK. But I met the signature related issue during android webview test.
Can anybody help analyze which part of my test could be the cause?
The test environment:
Android SDK 5.1 (since client certificate event callback API is opened since 5.0)
tomcat 8.0 https server, the type of server keystore is jks.
client keystore type is PKCS12, Both client private key and ca trust certificate(self-signed) are save in it.
I customize WebviewClient which code is shown below.
public class SSLWebViewClient extends WebViewClient {
private X509Certificate[] certificatesChain;
private PrivateKey clientCertPrivateKey;
private InputStream certfile_p12;
private String certfile_password = "";
private Context context;
public SSLWebViewClient(Context context) throws Exception {
super();
this.context = context;
initPrivateKeyAndX509Certificate();
}
private void initPrivateKeyAndX509Certificate() throws Exception {
KeyStore keyStore;
certfile_password = "123456";
certfile_p12 = context.getResources().getAssets().open("client.p12");
keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(certfile_p12, certfile_password.toCharArray());
clientCertPrivateKey = (PrivateKey) keyStore.getKey("client", certfile_password.toCharArray());
certificatesChain = new X509Certificate[1];
certificatesChain[0] = (X509Certificate)keyStore.getCertificate("server");
}
#Override
public void onReceivedClientCertRequest(WebView view, ClientCertRequest handler) {
if((null != clientCertPrivateKey) && ((null!=certificatesChain) && (certificatesChain.length !=0))){
handler.proceed(this.clientCertPrivateKey, this.certificatesChain);
}else{
handler.cancel();
}
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onReceivedSslError(final WebView view, SslErrorHandler handler,
SslError error) {
handler.proceed();
}
}
The handshake procedure I captured by ssldump is as follows.
2 1 0.0094 (0.0094) C>S Handshake ClientHello
2 2 0.0369 (0.0274) S>C Handshake ServerHello
Certificate
ServerKeyExchange
CertificateRequest
Not enough data. Found 266 bytes (expecting 32767)
ServerHelloDone
2 0.1244 (0.0874) C>S TCP FIN
2 0.1247 (0.0003) S>C TCP FIN
New TCP connection #3: 222.130.170.32(17617) <-> worknode(8443)
3 1 0.0074 (0.0074) C>S Handshake ClientHello
3 2 0.0373 (0.0299) S>C Handshake ServerHello
Certificate
ServerKeyExchange
CertificateRequest
Not enough data. Found 266 bytes (expecting 32767)
ServerHelloDone
3 3 0.1089 (0.0715) C>S Handshake Certificate
3 4 0.1089 (0.0000) C>S Handshake ClientKeyExchange
3 5 0.1089 (0.0000) C>S Handshake CertificateVerify
Not enough data. Found 258 bytes (expecting 16384)
3 6 0.1089 (0.0000) C>S ChangeCipherSpec
3 7 0.1089 (0.0000) C>S Handshake
3 8 0.1514 (0.0424) S>C Alert fatal bad_certificate
3 0.1514 (0.0000) S>C TCP FIN
3 0.3448 (0.1933) C>S TCP FIN
I notice that there are twice of ClientHello exists.
From the tomcat log, I find the first round of handshake is ended at
*** ServerHelloDone
http-nio-8443-exec-2, WRITE: TLSv1.2 Handshake, length = 1683
http-nio-8443-exec-4, called closeOutbound()
http-nio-8443-exec-4, closeOutboundInternal()
http-nio-8443-exec-4, SEND TLSv1.2 ALERT: warning, description = close_notify
http-nio-8443-exec-4, WRITE: TLSv1.2 Alert, length = 2
The second round handshake is ended at
*** CertificateVerify
Signature Algorithm SHA512withRSA
http-nio-8443-exec-6, fatal error: 42: certificate verify message signature error
javax.net.ssl.SSLHandshakeException: certificate verify message signature error
%% Invalidated: [Session-29, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA]
http-nio-8443-exec-6, SEND TLSv1.2 ALERT: fatal, description = bad_certificate
http-nio-8443-exec-6, WRITE: TLSv1.2 Alert, length = 2
http-nio-8443-exec-6, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: certificate verify message signature error
The detailed log of tomcat is posted on the link below.
https://raw.githubusercontent.com/watanuoli/ssllog/master/README.md
Well its about 5 years old but I had the same issue.
This line is important:
%% Invalidated: [Session-29, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA]
Whereat TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA is a ciphre!
This line means that the cipher has been invalidated by an server internal decision!
So the request is incomming from the browser to the server, the certificates are shared and the server decide - no matter if the certificate is valid, no matter if the chain-of-trust is valid no matter if access is granted or not, to reject the connection because the cipher has been invalidated by the server's internal configuration.
In order to allow this chiphre to be valid for data-transfer, add this chiphre to the allowed ciphers in the server's configuration.
For Apache Tomcat you have to edit the server.xml. The xml-node Server->Service->Connector(usually port 443)->SSLHostConfig has a xml-attribute called ciphers, add your invalidated cipher to this xml-attribute (,-seperated).
I guess you have to restart the server then.
I succefuly build pjsip library with OpenSSL. Now how can I configure TLS transport using pjsua2? After this:
TlsConfig tlsConfig = new TlsConfig();
sipTpConfig.setTlsConfig(tlsConfig);
try {
ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TLS, ipTpConfig);
} catch (Exception e) {
System.out.println(e);
}
Log tells, that "!SIP TLS listener is ready for incoming connections". But when I added new account, SIP registration failed with status=503(Connection refused). Here is asterisk configuration:
icesupport=yes
avpf=yes
qualify=yes
encryption=yes
dtlsenable=yes
dtlsverify = no
dtlsrekey = 60
dtlscafile = /var/lib/asterisk/keys/ca.crt
dtlscertfile = /var/lib/asterisk/keys/asterisk.pem
dtlssetup = actpass
Make sure that you are using the port that is not used. You can configure this after you instantiate TransportConfig.
TlsConfig tlsConfig;
tlsConfig.port = 6000;
It could also be your sip registration is not going through. Make sure that you are adding sip in front of the sipuserid like this:
"sip:555#s444.com;transport=tcp"
i am constantly monitoring my app errors and I see the following error too many times
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb8f0fc28: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xaa48cd5c:0x00000000)-javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb8f0fc28: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xaa48cd5c:0x00000000)
You can see the the error is about SSLV3 and my server support only TLSV1.2.
It seems like that on some clients Volley falls back to use SSLV3 (for some reason) and they get an error.
Users that get this error are on Android 4.4.2, 4.4.4 and 4.1.1 and more.
Interestingly enough I also use DefaultHttpClient in the same application, but it does not seem to report the same issue.
I am using the default HurlStack in Volley
I have seen the following...
Disable SSL as a protocol in HttpsURLConnection
and
https://code.google.com/p/android/issues/detail?id=78187
So what are my options?
Is my assumption correct that Volley falls back to SSLV3?
Why does volley fallback to SSLV3? In other words, what was the original failure that caused the fallback and how to resolve it?
i I downloaded Volley recently, but I am not sure it is the latest. How do I find which version I have?.
Any thoughts?
Your server does well not supporting SSLv3 since it has some security issues and should not be used.
When using Android versions prior to Kitkat you must use a socket factory that removes SSLv3 to be used as default configuration:
public class VolleyToolboxExtension extends Volley {
/** Default on-disk cache directory. */
private static final String DEFAULT_CACHE_DIR = "volley";
/**
* Creates a default instance of the worker pool and calls {#link RequestQueue#start()} on it.
*
* #param context A {#link Context} to use for creating the cache dir.
* #param stack An {#link HttpStack} to use for the network, or null for default.
* #return A started {#link RequestQueue} instance.
*/
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (PackageManager.NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
// Use a socket factory that removes sslv3
stack = new HurlStack(null, new NoSSLv3Compat.NoSSLv3Factory());
} else {
stack = new HurlStack();
}
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
/**
* Creates a default instance of the worker pool and calls {#link RequestQueue#start()} on it.
*
* #param context A {#link Context} to use for creating the cache dir.
* #return A started {#link RequestQueue} instance.
*/
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, null);
}
}
NoSSLv3Compat class can be found here:
https://github.com/Floens/volley/blob/master/src/com/android/volley/compat/NoSSLv3Compat.java
Use this extension to create your request queue:
/**
* #return The Volley Request queue, the queue will be created if it is null
*/
public RequestQueue getRequestQueue() {
// lazy initialize the request queue, the queue instance will be
// created when it is accessed for the first time
if (mRequestQueue == null) {
// Create the request queue
mRequestQueue = VolleyToolboxExtension.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
You could also use Retrofit instead of Volley, since Square released the 2.1 version of this library that supports TLS version configuration:
http://square.github.io/retrofit/
I am building an android app which is connecting to a server and retrieving data. First I got to choose whether I will be using AsynchTask (with HttoClient) or AsynchHttpClient, and i chose AsynchHttpClient. Now, actually everything is working fine, but today, when I was debugging something else, I noticed that the debugger throws a warning when I am sending/retrieving data(I am doing everything over https). The debugger says something like Beware! using the fix is insecure, as it doesn't verify SSL certificates. I was doing some digging, and I found this message inside of the AsynchHttpClient class, the actual part where it is comming from is here:
private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
if (fixNoHttpResponseException) {
Log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates.");
}
if (httpPort < 1) {
httpPort = 80;
Log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80");
}
if (httpsPort < 1) {
httpsPort = 443;
Log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443");
}
I am not quite sure which fix is meant. And yes i almost forgot, I read that it may be because I am using self signed certificates (for testing), but before i release something which isn't secure I thought I ask here if someone else knows what exactly this message means
Thanks
Maybe there is something wrong with your cetificates ?
I use this method to add my certificates in Android projects.
public static SSLContext getFactory() throws Exception {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.myfile);
try {
// Initialisation de notre keystore. On entre le mot de passe (storepass)
trusted.load(in, "mypassword".toCharArray());
} finally {
in.close();
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trusted);
SSLContext ssl_context = SSLContext.getInstance("SSL");
ssl_context.init(null, tmf.getTrustManagers(), null);
return ssl_context;
}
I have an android application that works on my home network and does not have these handshake errors. However when sending this app over to my client and testing it through their wifi network I get these logs.
E/chromium(15135): external/chromium/net/socket/ssl_client_socket_openssl.cc:792: [1211/175912:ERROR:ssl_client_socket_openssl.cc(792)] handshake failed; returned 0, SSL error code 5, net_error -107
W/chromium(15135): external/chromium/net/http/http_stream_factory_impl_job.cc:865: [1211/175912:WARNING:http_stream_factory_impl_job.cc(865)] Falling back to SSLv3 because host is TLS intolerant:
I have https URLS loaded in an android webview inside my application. I have no other information aside from these errors. Do you guys have any idea why this happens on a specific network, I am really out of ideas right now.
Recently I occurred a similar error during my test on connecting the specific server:
handshake failed; returned -1, SSL error code 1, net_error -103
I find some useful reason by searching from chromium source code,which indicates the meaning of ret code.Maybe it can help you find the reason.
SSL error code 5:
chromium//src/third_party/boringssl/src/include/openssl/ssl.h
/*
SSL_ERROR_SYSCALL indicates the operation failed externally to the library.
The caller should consult the system-specific error mechanism. This is
typically |errno| but may be something custom if using a custom |BIO|. It
may also be signaled if the transport returned EOF, in which case the
operation's return value will be zero.
*/
define SSL_ERROR_SYSCALL 5
net_error -107
// An SSL protocol error occurred.
NET_ERROR(SSL_PROTOCOL_ERROR, -107)
if you want to find more detail,the main function which print this log as below:
chromium//src/net/socket/ssl_server_socket_impl.cc
int SSLServerSocketImpl::DoHandshake() {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
int net_error = OK;
int rv = SSL_do_handshake(ssl_.get());
if (rv == 1) {
completed_handshake_ = true;
// The results of SSL_get_peer_certificate() must be explicitly freed.
bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl_.get()));
if (cert) {
// The caller does not take ownership of SSL_get_peer_cert_chain's
// results.
STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_.get());
client_cert_ = CreateX509Certificate(cert.get(), chain);
if (!client_cert_.get())
return ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT;
}
} else {
int ssl_error = SSL_get_error(ssl_.get(), rv);
OpenSSLErrorInfo error_info;
net_error = MapOpenSSLErrorWithDetails(ssl_error, err_tracer,
&error_info);
// SSL_R_CERTIFICATE_VERIFY_FAILED's mapping is different between client and
// server.
if (ERR_GET_LIB(error_info.error_code) == ERR_LIB_SSL &&
ERR_GET_REASON(error_info.error_code) ==
SSL_R_CERTIFICATE_VERIFY_FAILED) {
net_error = ERR_BAD_SSL_CLIENT_AUTH_CERT;
}
// If not done, stay in this state
if (net_error == ERR_IO_PENDING) {
GotoState(STATE_HANDSHAKE);
} else {
LOG(ERROR) << "handshake failed; returned " << rv << ", SSL error code "
<< ssl_error << ", net_error " << net_error;
net_log_.AddEvent(
NetLogEventType::SSL_HANDSHAKE_ERROR,
CreateNetLogOpenSSLErrorCallback(net_error, ssl_error,
error_info));
}
}
return net_error;
}