Im trying to connect a client to a server via SSL secure connection, but I seem to be thrown the "SSLHandshakeExceptin: no cipher suites in common" everytime. I could really use some help with this one.
Here is the server code:
public ChatServer() {
usedNames.add("arnold");
SSLServerSocket ss = null;
try {
SecureRandom sr = new SecureRandom();
String passphrase = "serverpwd";
//read a file with client certificates
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("client.public"), "public".toCharArray());
//reads a file with servers certificate and secret key
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("server.private"), passphrase.toCharArray());
// tmf,kmf and sslContext
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(clientKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(serverKeyStore, passphrase.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);
// Create socket
SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ss = (SSLServerSocket) factory.createServerSocket(serverPort);
ss.setNeedClientAuth(true); // client needs to have auth.
ss.setEnabledCipherSuites(new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA"});
} catch (Exception e) {
System.err.println("[system] could not create socket on port " + this.serverPort);
e.printStackTrace(System.err);
System.exit(1);
}
// start listening for new connections
System.out.println("[system] listening ...");
try {
while (true) {
Socket socket = ss.accept(); // connection established
((SSLSocket)socket).startHandshake(); //explicitly trigger SSL handshake
String username = ((SSLSocket) socket).getSession().getPeerPrincipal().getName();
And here is the client code:
SecureRandom sr = new SecureRandom();
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("server.public"), "public".toCharArray());
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream(sslPrivate), passphrase.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(serverKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(clientKeyStore, passphrase.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);
// create socket
SSLSocketFactory sf = sslContext.getSocketFactory();
socket = (SSLSocket)sf.createSocket("localhost", serverPort);
socket.setEnabledCipherSuites(new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA" }); //(CipherSuite)
socket.startHandshake(); // //explicitly trigger SSL handshake
This is what prints out on the console where i run the "server":
And this is on the console where i run the "client":
Related
I want to secure my http request ,Im using something like http://123.456.789.123:1234 and I want secure it. I create a keystore.csr carets.jks server.cer and keystore.jks with the java keytool after that I implement my code, but it can't read HttpsParameters
String alias = "alias";
char [] storepass = "changeit".toCharArray();
String keystoreName = "c:\\keystore.jks";
FileInputStream in = new FileInputStream(keystoreName);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(in, storepass);
Certificate cert = keystore.getCertificate(alias);
Log.debug("the certification is here : " + cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
char [] keypass = "changeit".toCharArray();
kmf.init(keystore, keypass);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 0);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
SSLContext c = SSLContext.getDefault();
SSLEngine engine = c.createSSLEngine();
params.setNeedClientAuth(false);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
SSLParameters defaultSSLParameters=c.getDefaultSSLParameters();
params.setSSLParameters(defaultSSLParameters);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Failed to create HTTPS server");
}
}
});`
I did a mistake that I forgot to add the import to my class
import com.sun.net.httpserver.HttpsParameters;
I am trying to send data from my client to my server. Therefore I am using TSL.
I created the certificates and these are loaded without any troubles.
The connection is established, but the handshake between the client and the server is never called, and the handshakeCompleted is never called.
Client:
char[] password = "Password".toCharArray();
KeyStore trustStore = KeyStore.getInstance("BKS");
trustStore.load(activity.getResources().openRawResource(R.raw.truststore), password);
Log.i("Update", "Loaded trust certificate");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
Log.i("Update", "Loaded trustManagerFactory");
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(activity.getResources().openRawResource(R.raw.keystore), password);
Log.i("Update", "Loaded key certificate");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
Log.i("Update", "Loaded keyManagerFactory");
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
Log.i("Update", "Loaded SSLContext");
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
final SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(InetAddress.getByName(host), port);
Log.i("Update", "Loaded SSL
socket.addHandshakeCompletedListener(new HandshakeCompletedListener(){
#Override
public void handshakeCompleted(HandshakeCompletedEvent handshakeCompletedEvent){
try{
Log.i("Update", "Did handshake");
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
Log.i("Update", "Writer");
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.i("Update", "Reader");
while(isRunning){
try{
writer.println("Test");
writer.flush();
Log.i("DATA", "DATA SENT");
}catch(Exception e){
e.printStackTrace();
}
}
writer.close();
reader.close();
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
});
socket.startHandshake();
Server:
char[] password = "Password".toCharArray();
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(getClass().getResourceAsStream("/security/keystore.jks"), password);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
SSLServerSocket serverSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(7826);
System.out.println("Accepting connections now...");
while(true){
SSLSocket socket = (SSLSocket) serverSocket.accept();
socket.setUseClientMode(false);
socket.addHandshakeCompletedListener(handshakeCompletedEvent -> {
try{
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
while(running){
if(!socket.isConnected() || socket.isClosed()){
disconnect();
return;
}
for(Iterator<String> pendingIterator = pendingMessages.iterator(); pendingIterator.hasNext();){
String message = pendingIterator.next();
pendingIterator.remove();
writer.println(message); writer.flush();
}
//Auto decrypt when message arrives, but no thread blocking
if(reader.ready()){
String line = reader.readLine();
System.out.println(line);
}
}
}catch(Exception e){
e.printStackTrace();
}
});
socket.startHandshake();
}
As you can see I am waiting on both sides for the handshakeComplete, using it only on the client or only on the server side doesn't work either
I tried to make an Android Server with an SSLServerSocket. I made a keystore and started to make the server. I initialize the server as follows:
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
InputStream inputStream = context.getResources().openRawResource(R.raw.server);
keyStore.load(inputStream, "passwd".toCharArray());
String keyalg = KeyManagerFactory.getDefaultAlgorithm();
kmf.init(keyStore, "passwd".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyalg);
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), null, null);
SSLServerSocket ss = (SSLServerSocket) context.getServerSocketFactory().createServerSocket();
inputStream.close();
//Here comes the error
ss.accept();
So if I try to accept clients (without that the client side tried to connect), I get an error.
java.net.SocketException: accept failed: EINVAL (Invalid argument)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:110)
at java.net.ServerSocket.implAccept(ServerSocket.java:203)
at com.android.org.conscrypt.OpenSSLServerSocketImpl.accept(OpenSSLServerSocketImpl.java:184)
at de.turtc.util.ServerUtil.run(ServerUtil.java:88)
Caused by: libcore.io.ErrnoException: accept failed: EINVAL (Invalid argument)
at libcore.io.Posix.accept(Native Method)
at libcore.io.BlockGuardOs.accept(BlockGuardOs.java:55)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:98)
Without a SSLServerSocket it works! I dont get any information of this error!
Problem was: I didn't give a port to the server.
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
InputStream inputStream = context.getResources().openRawResource(R.raw.server);
keyStore.load(inputStream, "passwd".toCharArray());
String keyalg = KeyManagerFactory.getDefaultAlgorithm();
kmf.init(keyStore, "passwd".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyalg);
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), null, null);
SSLServerSocket ss = (SSLServerSocket) context.getServerSocketFactory().createServerSocket(4444);
inputStream.close();
ss.accept();
So I changed:
SSLServerSocket ss = (SSLServerSocket) context.getServerSocketFactory().createServerSocket();
to
SSLServerSocket ss = (SSLServerSocket)context.getServerSocketFactory().createServerSocket(4444);
That solved my problem!
I am establishing an SSL connection to a server which has enabled ssl.There is a cacerts file in my hardware's filesystem java keystore and I extracted the certificate from it using keytool & I am giving this certificate file to create an SSLSocketfactory to establish the ssl connection , which works fine with the code snippet below.
I wanted to know how to access the cacerts ( java keystore ) file directly , and pick the certificate and establish the ssl connection. Right now , I am packaging the extracted certicate in the classpath with my jar file , which is not a good practice as I want it to be loaded from the keystore.
Below is the working code snippet of how I create a SSLSocketFactory currently.
private SSLSocketFactory createSSLFactory() {
KeyStore keyStore = null;
TrustManagerFactory tmf = null;
SSLContext ctx = null;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = null;
is = SSLConnection.class.getResourceAsStream("/" + "my-keystore");
keyStore.load(is, "changeit".toCharArray());
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();
return factory;
} catch (Exception e) {
// exception handling
}
return null;
}
It doesn't make any sense to embed a KeyStore into a JAR file in the case of private keys and authenticating certificates. A client certificate is supposed to uniquely identify the client. It is a property of a host, not a JAR file, which can be copied around infinitely. It doesn't make sense to allow the use of the same client certificates for multiple clients. It is a misuse of PKI.
You can pass the keystore (and truststore) as system properties to the JVM. See here: https://stackoverflow.com/a/882479/131929
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS
Then you can do
URL url = new URL("https://someurl");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
InputStream inputstream = conn.getInputStream();
You need to add a trust manager :
SSLSocketFactory factory = null;
try {
SSLContext ctx;
KeyManagerFactory kmf;
TrustManagerFactory tmf;
KeyStore ks;
char[] passphrase = "passphrase".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
tmf = TrustManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("testkeys"), passphrase);
kmf.init(ks, passphrase);
tmf.init(ks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
factory = ctx.getSocketFactory();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
I'm trying my to create TLS v1.2 communication between a server and android client.
I established a TLS v1.0 connection with any problem, but I cannot get v1.2.
This is server code:
char[] passphrase = "myComplexPass1".toCharArray();
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream("cacerts"), passphrase);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keystore, passphrase);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
SSLContext sslContext.init(keyManagers, null, null);
SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(port);
sslServerSocket.setEnabledProtocols(new String [] { "TLSv1", "TLSv1.1", "TLSv1.2" });
sslServerSocket.setUseClientMode(false);
sslServerSocket.setWantClientAuth(false);
sslServerSocket.setNeedClientAuth(false);
sslSocket = (SSLSocket)sslServerSocket.accept();
while this is client code:
char[] passphrase = "myComplexPass1".toCharArray();
KeyStore keystore = KeyStore.getInstance("BKS");
keystore.load(this.getApplicationContext().getResources().openRawResource(R.raw.jb), passphrase);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, passphrase);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
Log.d("Context Protocol",sslContext.getProtocol());//this prints correctly TLS v1.2!
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManager[] trustManagers = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
}
}
};
sslContext.init(keyManagers, trustManagers, new SecureRandom());
SSLSocketFactory sslSocketFactory = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket skt = (SSLSocket) sslSocketFactory.createSocket(HOST, PORT);
skt.setKeepAlive(true);
Client code, written in a java client running on JRE7 on my pc, perfectly works and I see with getProtocol (server-side) TLSv1.2 with a correct cipher, supported by tlsv1.2.
Same code on android make a tlsv1.0 connection!
I really don't uderstand.
On Java client JRE7 works, on android ONLY tlsv1.0
Any suggestion?
It's my first question, I searched a lot. Probably my formatting is not correct :(
Kind of late to be answering this, but maybe someone else will need an answer.
I have run into the same issue. No matter whether you provide TLSv1.2 to the SSLContext.init() method, some Android versions that I've tried do not enable TLS 1.2. You must enable that on your client socket using setEnabledProtocols() just as you do for your server socket. For me, I did this in a custom SSLSocketFactory I created:
public class MySSLSocketFactory extends SSLSocketFactory
throws NoSuchAlgorithmException {
private SSLContext mSSLContext;
public MySSLSocketFactory(KeyManager km) {
...
mSSLContext = SSLContext.getInstance("TLSv1.2");
...
mSSLContext.init(new KeyManager[] {km}, null, null);
...
}
#Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
throws IOException {
SSLSocket s = (SSLSocket)mSSLContext.getSocketFactory().createSocket(socket, host, port, autoClose);
s.setEnabledProtocols(new String[] {"TLSv1.2"} );
return s;
}
...
}