JAVA SSL: how to get client certificate information - java

I have an SSL-enabled tcp server that can listen to multiple rsyslog clients. Each client has its own certificate that is added in the server's truststore. This setup is working fine. TThe question is whether there is a way to get the client certificate information like CN, location etc. after the socket accepts connection?
Below is the code sample of simple tcp server.
SSLServerSocketFactory sf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = sf.createServerSocket(514);
while(true){
SSLSocket s = (SSL)ss.accept();
// here I need to get client certificate information
}

You need to configure the SSLServerSocket to need or want client authentication, depending on which of those applies. Then you can get the peer certificates out of the SSLSocket's SSLSession, if they were sent.

Related

Question about Java SSL connection between client and server

So I'm wanting to set up an SSL server/client in Java, my knowledge with networking is not very good I've created normal servers/clients in java many times and wanted to up it and setup SSL so a user can't just send false packets to my client thinking its the server sending them.
I've looked up a few examples etc and came across this GitHub repo which shows a basic server with SSL encryption between the client and server and set it up in my IDE.
Here is the repo:
https://github.com/AlphaGarden/SSL-Client-Server
My question is why does the client and server use both certificates? Can't a user just get the certificates from the client and use them to decrypt the SSL? Also in the client there's 2 strings, password & password2... Am I supposed to hide these from the person using my client too? If not am I supposed to hide anything client sided from the user that could help them decrypt the SSL traffic and feed my client false information?
Just some basics to explain a SSL/TLS connection: Wkipedia https://en.wikipedia.org/wiki/Transport_Layer_Security, for TLS 1.2 RFC5246: https://www.rfc-editor.org/rfc/rfc5246 and for TLS 1.3 RFC8446 https://www.rfc-editor.org/rfc/rfc8446.
The basic principle for a secure connection is to use (each) a certificate on server and client's side and exchange them. The certificate itself is useless as it does not prove that you are whom you say to be. To get trust in the certificate the usual way is to "buy" a certificate from a Certificate Agency (CA) that checks your identity.
The CA's root certificate usually is known to today browsers and so the server and client certificate can get checked
by the browser (client) and server against the CA's root certificate.
Let us see the code for the simple SSL Server & Client code. I'm for sure you noticed that the server and client are using
"twisted" sources for the keystore and the truststore and therefore they need two (different) passwords to get access to the two stores:
SSLServer:
String password = "abcdefg";
InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("server/certificate-server.p12");
// TrustManagerFactory
String password2 = "aabbcc";
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
InputStream inputStream1 = ClassLoader.getSystemClassLoader().getResourceAsStream("client/certificate-client.p12");
SSLClient:
String password = "aabbcc";
InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("client/certificate-client.p12");
// TrustManagerFactory ()
String password2 = "abcdefg";
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
InputStream inputStream1 = ClassLoader.getSystemClassLoader().getResourceAsStream("server/certificate-server.p12");
What are the keystore and the truststore good for? The keystore holds the (own) private key (of server and client) and in the truststore (all) trusted certificates (usually the CA root certificates) are saved. To check the received certificate from the other party the server and client prove the certificate chain up to the root certificate from the CA.
But here is the problem - as the programs are using self signed certificates there is not "real" and saved root certificate available in the trust store. To get the programs to run without an user interaction ("do you trust this certificate ?") both provide use a truststore with the "approved" certifcates and all is running.
To your second question "Can't a user just get the certificates from the client and use them to decrypt the SSL" the answer is simple: YES. But when securing a communication only between "allowed" partners - how should e.g. the servers knows that the client is the real one and not an attacker? For that reason the client is sending a certificate as well that can get checked by the servers
truststore.

Create self-signed SSL socket from Java client (on Android) to Python server

I created a self-signed certificate (server.crt, server.key, server.p12). I get a Python-Python SSL socket connection using this self-signed certificate working just fine.
Python server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 10023))
s.listen(5)
s_, fromaddr = s.accept()
connstream = ssl.wrap_socket(s_,
server_side=True,
certfile="server.crt",
keyfile="server.key")
data = connstream.read()
...
Now, I would like my Android application to talk with my Python server. I can get a non SSL connection going. I'm not sure how to proceed with self-signed certificates. My understanding is that I have to store the certificate in Java's truststore. I am having difficulty finding examples of doing this within the Android app (programmatically) using a trusted certificate file (e.g. the crt?). Obviously, the scope of this trust is limited to the app only, and is not intended to be a permanent solution.
Java client (on Android):
SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = ssf.createSocket(HOST, PORT);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("hello from java!");
out.flush();
...
When I try to connect I get the following error on the server:
ssl.SSLError: [Errno 1] _ssl.c:499: error:14094416:SSL routines:SSL3_READ_BYTES:sslv3 alert certificate unknown
export crt file at server
import crt file from asserts or file at Android code
set up crt with TrustManagerFactory at Android code
init SSLContext with TrustManagerFactory
this is reference on official document

How to use SSL in Java correctly?

Unfortunately I'm completely new to SSL. Currently I'm trying to set up a secure connection between a client and a server application in Java and the following code works for me (transmitted data is encrypted), but I don't know if this is a correct and secure solution.
Client side:
socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port);
socket.setUseClientMode(true);
socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
socket.startHandshake();
Server side:
sslServerSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(requestPort());
sslServerSocket.setUseClientMode(false);
sslServerSocket.setEnabledCipherSuites(sslServerSocket.getSupportedCipherSuites());
It is not advisable to enable all ciphers/protocols. Better that you enabled only the ciphers and protocols you want. If both server and server is written by you, choose what you want and configure only that.
socket.setEnabledCipherSuites(...);
socket.setEnabledProtocols(...);
Supported ciphers and protocols can be seen in JSSE documentation
Or you can use "jdk.tls.disabledAlgorithm" to control what algs you want to use.

Creating an SSL connection between an Android app and TCP server

I have an Android app which uses a Java TCP client to connect to a Java TCP application server.
In some cases I noticed firewalls or routers that block the port I am using can cause issues so I am trying to use a secure connection.
I have tried using the examples from this link:
SSLServerSocket but I am always getting a connection timeout.
Server code:
ServerSocketFactory sslServerSocketFactory = SSLServerSocketFactory.getDefault();
serverSocket = sslServerSocketFactory.createServerSocket(port, backlog);
Socket socket = serverSocket.accept(); ---> in a new thread
Client code:
SocketFactory socketFactory = SSLSocketFactory.getDefault();
clientSocket = socketFactory.createSocket();
clientSocket.connect(new InetSocketAddress(host, port), READ_TIMEOUT); ---> timeout on this line
I also tried the more complicated examples in the link but all resulted in a timeout.
I really want to understand what's wrong with this very simple example.
If it's not the way to work with SSL (I see no mention of certificates in this code at all, which I think is necessary in SSL) then why is it given as a working example?
Any help would be appreciated.

Can not establish SSL-Connection

I have a server (java) and a client (android -smartphone).
I want the client to send encrypted data(GPS location, via SSL) to the server.
I want to be the only one who is able connect to my server.
For this I created:
serverKeyStore.jks (containing servers private key)
clientKeyStore.jks (containing clients private key)
serverTrustStore.jks (containing clients certificate exported from clientKeyStore)
clientTrustStore.jks (-||- from serverKeyStore)
That way the server trusts the client and the client trusts the server. (from the certificate point of view) No one else can connect to my server because the server will not trust the unknown client and will terminate the connection.
For this I did setup the server(only SSL-related part):
System.setProperty("javax.net.ssl.keyStore", "C:\\serverKeyStore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pw);
System.setProperty("javax.net.ssl.trustStore", "C:\\serverTrustStore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pw);
ServerSocketFactory gpsServerSocketFactory = SSLServerSocketFactory.getDefault();
gpsServerSocket = gpsServerSocketFactory.createServerSocket(gpsSocketPort);
while(true)
{
Socket newConnection = gpsServerSocket.accept();
new NewGPSConnectionThread(newConnection).start();
}
Hoping that this is enough an the SSLContext is now using serverKeyStore.jks and serverTrustStore.jks setted via System-Properties.
The Client-Side is where I struggle:
I added the clientKeyStore.jks and the clientTrustStore.jks to the assets-folder. I know that I can not directly refer to the file in the assets folder as the application is going to be compressed. (apk)
But I am not able to figure out how to configure the SSLSocket on the client side to use the clientKeyStore.jks and clientTrustStore.jks being able to establish a secure connection.
The ssl related part of my client-program:
SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
gpsSocket = sslSocketFactory.createSocket(MainActivity.dstName, MainActivity.dstPortGPS);
But it is clear that the SSLContext or SSLSocket is not aware of my clientKeyStore.jks and clientTrustStore.jks and will not refer to default ones.
The questions:
1) Is my server ssl-configuration finished?
2) How can I finish my client ssl-configuration? How can I bring client-key- and truststore into game?

Categories

Resources