I try establish a https server in android for other phones to connect,but
only iphone6 sometimes can connected , ipod ,android browser all failed to get the webserver content.
(the browser message is fail to establish safe connect)
I use nanohttpd's simpleServer Class to establish it.
my CA is here
http://www.mediafire.com/download/53f6e9uveb47kqv/ca.cer
// for client to download
http://www.mediafire.com/download/v9i58n38yb85co5/server.p12
//for server to load keystore
CA password both are singuler .
Here is my sslServerSocket Code
char[]kspass = KEYSTOREPASS.toCharArray();
char[]ctpass = KEYSTOREPASS.toCharArray();
try {
KeyStore ks = KeyStore.getInstance("PKCS12");
//ks.load(new FileInputStream("file:///android_asset/singuler.keystore"),kspass);
ks.load(getResources().getAssets().open("server.p12"),kspass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, ctpass);
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("X509");
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
//webServer.makeSecure(NanoHTTPD.makeSSLSocketFactory(ks, kmf.getKeyManagers()));
webServerSSL.makeSecure(sc.getServerSocketFactory());
} catch (Exception e) {
// TODO: handle exceptionser
Log.i("test", e.toString());
}
try {
webServer.start(15);
webServerSSL.start(15);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
webServer = null;
webServerSSL=null;
Log.i("test", e.toString());
}
Can any one help me ?
Thank you.
I found the answer
Whe start nanohttpd server , need set the timeout millonseconds for every connect socket,especial for https request.
Related
Attempting to establish an SSLSession using a self-signed certificate and the new-ish Network Security Configuration method as well as cwac-netsecurity library for backward compatibility works on all other versions of android (that I have tried) except Android 7.0.
I have an android app that connects to a device to provide a UI for that device. The connection uses a TLSv1 SSLSocket and a self-signed server certificate on the device side. Prior to Nougat, I had the server certs embedded as a BKS key store and loaded at run-time to create a custom TrustManager in order to intialize the SSL context and create the socket. This no longer works under Android 7+. Following some other questions on SO (Cannot connect via SSL using self signed certificate on Android 7 and above), I was able to use the Network Security Configuration method to establish the SSLSocket connection on an Android 8 device (https://developer.android.com/training/articles/security-config#ConfigCustom). For backward compatibility, I am using the cwac-netsecurity library from CommonsWare (https://github.com/commonsguy/cwac-netsecurity). I built a small test application and am testing against openssl s_server. What I have written establishes an SSLSession successfully from android devices running 4.4, 6.0, and 8.0. For some reason however, it does not do so on an android device running 7.0. Here are code snippets that show the test. Any help would be appreciated.
Test code in android app
{
// createSocketFactory
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); //null;
TrustManagerBuilder tmb = new TrustManagerBuilder();
tmb.withManifestConfig(MainActivity.this);
tmb.withCertChainListener(
new CertChainListener()
{
#Override
public void onChain(X509Certificate[] chain, String domain)
{
if (domain == null)
{
Log.d(TAG, "onChain: Certificate chain for request to unknown domain");
}
else
{
Log.d(TAG, "onChain: Certificate chain for request to: " + domain);
}
for (X509Certificate cert : chain)
{
Log.d(TAG, "onChain: Subject: " + cert.getSubjectX500Principal().getName());
Log.d(TAG, "onChain: Issuer: " + cert.getIssuerX500Principal().getName());
}
}
});
CompositeTrustManager ctm = tmb.build();
try
{
SSLContext sc = SSLContext.getInstance("TLSv1");
sc.init(null, new TrustManager[] { ctm }, new SecureRandom());
factory = sc.getSocketFactory();
}
catch (NoSuchAlgorithmException e)
{
Log.e(TAG, "createSocketFactory: failed to get SSLContext", e);
}
catch (KeyManagementException e)
{
Log.e(TAG, "createSocketFactory: failed to init SSLContext from CompositeTrustManager");
}
// createSslSocket
SSLSocket socket = null;
String addr = "172.31.106.60";
int port = 50001;
if (factory != null)
{
Log.d(TAG, "createSocketFactory - SUCCESS");
try
{
socket = (SSLSocket)factory.createSocket(addr, port);
Log.d(TAG, "createAltSocket - SUCCESS");
socket.setEnabledProtocols(new String[] { "TLSv1" });
socket.setEnabledCipherSuites(new String[] { "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" });
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
}
catch (IOException e)
{
Log.e(TAG, "createSslSocket - Couldn't create SSLSocket", e);
try
{
socket.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
finally
{
socket = null;
}
}
}
else
{
Log.d(TAG, "createSocketFactory - FAILED");
}
// testSslSocket
if (socket != null && socket.isConnected())
{
SSLSession session = socket.getSession();
if (session != null && session.isValid())
Log.d(TAG, "testSslSocket: SESSION SUCCESS");
else
Log.d(TAG, "testSslSocket: SESSION FAILED");
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
network_securiity_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="#raw/test_cert_chain"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.ssltesting">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:networkSecurityConfig="#xml/network_security_config">
<meta-data
android:name="android.security.net.config"
android:resource="#xml/network_security_config" />
test server
openssl s_server -tls1 -WWW -accept 50001 -cert test.crt -key mcv.key -state
In all working cases, the SSLSession is valid at the end of the test routine, and I get logging from the CertChainListener. However, when running this on my Android 7.0 device, all is quiet. I get no logging from the CertChainListener, the SSLSession is not valid, and I get the following on the server side:
Using default temp DH parameters
ACCEPT
SSL_accept:before/accept initialization
SSL3 alert write:fatal:handshake failure
SSL_accept:error in error
140386525526784:error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher:s3_srvr.c:1417:
ACCEPT
I am using the org.apache.commons.net.FTPSClient in Android and I am trying to connect to a FTP Server via FTPS.
The connect method of the FTPSClient is very slow and this seems to depend on the Android Version.
On a Nexus 6 with Android 6.0.1 the connect call needs 5 sec in average.
On a Galaxy Nexus with Android 4.3 it only needs 1-2 sec in average.
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(
null,
new TrustManager[]{...<custom trust manager stuff>...},
null
);
} catch (NoSuchAlgorithmException nsae) {
FileLog.e(TAG, "No such algorithm: TLS: " + nsae.getMessage());
return null;
} catch (KeyManagementException kme) {
FileLog.e(TAG, "Key management problem: " + kme.getMessage());
return null;
}
FTPSClient client = new FTPSClient(sslContext);
client.setControlEncoding("UTF-8");
client.connect(ip, port); // <---- needs a long time
Has anyone experienced the same problem or has a possible solution to decrease the amount of time the connect call needs?
Firstly,
I want to use session ticket in android, My code as follows:
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext cpmContext = SSLContext.getInstance("TLSv1.2");
cpmContext.init(null, null, null);
SSLSocket socket = (SSLSocket) cpmContext.getSocketFactory().createSocket(ip, port);
socket.setEnabledProtocols(socket.getEnabledProtocols());
socket.setEnabledCipherSuites(socket.getEnabledCipherSuites());
Class c = socket.getClass();
try {
Method m = c.getMethod("setUseSessionTickets",boolean.class);
m.invoke(socket,true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
SSLSession session = socket.getSession();
I capture the data blcok by tcpdump, the code can get "
TLSv1.2 224 New Session Ticket, Change Cipher Spec, Hello Request, Hello Request"
,so I think I get the session ticket, but when I reconnect to server, "session ticket "content of client hello is as follow:
"Extension:sessionTicket TLS
Type: SessionTicket TLS(0x0023)
length:0
Data:(0 bytes)"
it did not execute resume.
then I use SSLCertificateSocketFactory to create SSLSocket:
private Socket createSocketOnLine(final String ip, final int port) throws UnknownHostException, IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, KeyManagementException {
SSLCertificateSocketFactory sf = (SSLCertificateSocketFactory) SSLCertificateSocketFactory
.getDefault(30 * 1000);
SSLSocket socket = (SSLSocket) sf.createSocket(ip, port);
socket.setEnabledProtocols(socket.getEnabledProtocols());
socket.setEnabledCipherSuites(socket.getEnabledCipherSuites());
enableSessionTicket(sf, socket);
SSLSession session = socket.getSession();
return socket;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public void enableSessionTicket(SSLCertificateSocketFactory sf, Socket socket) {
if (VERSION.SDK_INT > 17) {
sf.setUseSessionTickets(socket, true);
}
}
this code donot even enable session and the version of tls is always TLSv1.0,who can tell me how to enable it and set version of tls to be tlsv1.2?
PS:I test it on android 4.4 and L
Android's SSLCertificateSocketFactory is broken for you on some/many devices. It does not provide an interface/method for you to specify the enabled protocols. Instead, it simply uses the system default for the enabledProtocols. On earlier Android devices, that would be TLS and SSL3 and not TLSv1.2.
Because of the way it is implemented, you can't subclass it and attempt to override its behavior. There is no way for you to set the TLS protocol you want, let alone to set the ciphersuites that you may need to control.
Unfortunately, some of the other features of SSLCertificateSocketFactory are lost as well. For example, you can't enable SNI or set alpns protocols "officially" without it.
Thus, your solution will need to subclass SSLSocketFactory to provide your own socketfactory to control the settings you need as you do in your first code example. You can use your reflection trick above to enable session tickets in your own createSocket() method implementations.
I'm using gottox socket.io java client for an Android chat application. I could connect to both web-socket and Xhr transport in HTTP mode. But when i switch to HTTPS only Xhr mode is working. i used the default SSL Context as below
SocketIO.setDefaultSSLSocketFactory(SSLContext.getInstance("Default"));
This works fine in Xhr mode. But in websocket transport there are no responses or errors.
Update
It might be that with new versions IO.setDefaultSSLContext and IO. setDefaultHostnameVerifier methods are not available. Instead now we can create our own OkHttpClient and set the hostname verifier and ssl socket factory etc on it as mentioned on socket.io-client-java usage. Here is the sniplet from there:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.hostnameVerifier(myHostnameVerifier)
.sslSocketFactory(mySSLContext.getSocketFactory(), myX509TrustManager)
.build(); // default settings for all sockets
IO.setDefaultOkHttpWebSocketFactory(okHttpClient);
IO.setDefaultOkHttpCallFactory(okHttpClient);
Initial Answer:
I had the same issue with io.socket:socket.io-client:0.7.0 version of socket.io library on Android for long. It used to work fine for http protocol, however for https protocol it had trouble establishing connection giving xhr poll errors.
Following solution works for me without modifying the library itself:
// Socket connection
private Socket mSocket;
// Configure options
IO.Options options = new IO.Options();
// ... add more options
// End point https
String yourEndpoint = "https://whatever.yoururl.com"
String yourHostName = "yoururl.com"
// If https, explicitly tell set the sslContext.
if (yourEndpoint.startsWith("https://")) {
try {
// Default settings for all sockets
// Set default ssl context
IO.setDefaultSSLContext(SSLContext.getDefault());
// Set default hostname
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify(yourHostName, session);
}
};
IO.setDefaultHostnameVerifier(hostnameVerifier);
// set as an option
options.sslContext = SSLContext.getDefault();
options.hostnameVerifier = hostnameVerifier;
options.secure = true;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
// Instantiate the socket
mSocket = IO.socket(mEndpoint, options);
Hope this helps.
It works but you have to do some modifications on io.socket library.
Instead of using the socketio.jar, import into src folder the io.socket library (You'll find inside socket.io-java-client package). There, you have to edit the WebsocketTransport class.
Here you have the solution
https://github.com/Gottox/socket.io-java-client/issues/60
public WebsocketTransport(URI uri, IOConnection connection) {
super(uri);
this.connection = connection;
SSLContext context = null;
try {
context = SSLContext.getInstance("TLS", "HarmonyJSSE");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
try {
context.init(null, null, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
if("wss".equals(uri.getScheme()) && context != null) {
this.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(context));
}
}
And remember to call the setDefaultSSLSocketFactory like this:
socket = new SocketIO();
socket.setDefaultSSLSocketFactory(SSLContext.getDefault());
socket.connect("https://www.myHttpsServer.com:443/");
Hope it helps someone ;)
Websocket with SSL working in AndroidAsync. Using that for now.
I have a working ASP.NET Web API service running in Visual Studio on my dev box. I can easily get the proper results from either I.E. or FireFox by entering: http://localhost:61420/api/products. But when trying to read it from my Android Project using my AVD I get an exception thrown saying:
localhost/127.0.0.1:61420 - Connection refused.
I know my Android Java code works because I can access the WCF RESTFul service running on my Website (the URLthat's currently commented out). My Android code is pasted below.
So, why am I getting the error when accessing from my Eclipse project but not when accessing it from a browser?
Thanks
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
HttpURLConnection urlConnection = null;
try
{
//URL url = new URL("http://www.deanblakely.com/myRESTService/SayHello");
URL url = new URL("http://localhost:61420/api/products");
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
String myString = readStream(in);
String otherString = myString;
otherString = otherString + " ";
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
urlConnection.disconnect();
}
}
private String readStream(InputStream is)
{
try
{
ByteArrayOutputStream bo = new ByteArrayOutputStream();
int i = is.read();
while(i != -1)
{
bo.write(i);
i = is.read();
}
return bo.toString();
}
catch (IOException e)
{
return "" + e;
}
}
}
Visual Studio development web server will only accept connections from the local host and not over the network or other virtual connection. Sounds like AVD is seen as a remote host.
To access the app from anywhere, change the webserver that should be used. Assuming you're using Windows 7 and Visual Studio 2010, make sure you have IIS and all required features installed and set the local IIS as the webserver in your project settings:
It could be necessary to start Visual Studio as a Administrator to run it with local IIS.
Use the actual IP address of your machine ie, http://192.168.0.xx
Only your local machine can access localhost, and if you are on the emulator or a device, it will have a different IP through either NAT or your DHCP from the router.