How to verify a certificate using Keytool? - java

I want to a program to verify to create a SSL Sockets using Oracle's SSLSocket class. In my program I want the client to pass its certificate (created using Keytool). The Server should verify the certificate and then proceed with communication. I want the server to check the certificate of each client that connects to it. Suppose that all the key's (server's and client's) are stored in the Keystore. How do I implement this?
Edit:
Forgive me if I am not able to convey my question correctly. I am new to this. I'm reading this link to get some directions. Here, while reading the keystores the server has directly hard-coded the client's key file name (viz "client.public"). However, in my program this will be specified by the client as the server can't know beforehand what the client's public key file name would be.

You've just described exactly what already happens behind the scenes. All you have to do is create an SSLServerSocket and set needClientAuth to true, and start accepting connections from it as usual. JSSE will do the rest.

Related

SSL: How to handle multiple clients with separate keys connecting to the same port?

Another legacy support problem here!
We have a server multiple clients network where each component has a self signed certificate and is added to the server/client's trust store. We are not using a Certificate Authority here.
Now our problem is that we need to upgrade all the certificates for better security. The new clients will come with newer certificates and even the server will have new certificates.
Our problem is how to handle the old clients. Upgrading keystores of our old clients is the last resort.
Things that won't work:
Adding both the new and old certificates in server truststore: Even the clients are authenticating the servers and the server certificate will not be present in the client truststore.
Using new port for the new clients: We considered using new ports for new clients and continuing the old ports for old clients but the problem is that there are multiple applications which are facing this problem so we will have to search for multiple new ports which are not being used by other products.
FWIW: The servers are in Java and the clients are in C++
EDIT after EJP's answer
I am probably asking a very dumb question here but just wanted to be sure. There is absolutely no way to edit the SSL Context of a socket once it is bound. Correct?
Also, can we choose the server certificate to be used during the handshake? I know of chooseClientAlias() and chooseServerAlias() methods but here we don't know which certificate to use till the client Hello message is sent.
Leaving aside using different ports:
(1) will work as far as the server is concerned with the client certificates.
Nothing will work in terms of getting old clients to recognize the new server certificate, other than upgrading the client truststores.
This is why you should have used a CA, even an internal one, and why you should absolutely not make the same mistake again. If the clients had trusted the CA instead of a self-signed server certificate directly, you would not now have this problem, and you won't have it in future, however many times you upgrade the certificates, until the CA certificate expires, which should take 20 years.
And while you're at it, make sure you build in a way to update client truststores.
There is absolutely no way to edit the SSL Context of a socket once it is bound. Correct?
There is no way to edit the SSLContext once it is initialized, which precedes creation of sockets, let alone binding them. Hmm, maybe you could reload the KeyManager and TrustManager and just not tell the SSLContext, but I'm not saying it would (or wouldn't) work.
Also, can we choose the server certificate to be used during the handshake?
Yes, that's what the KeyManager interface is for, specifically chooseServerAlias().
I know of chooseClientAlias() and chooseServerAlias() methods but here we don't know which certificate to use till the client Hello message is sent.
chooseServerAlias isn't called until the ClientHello has been received.

Do Java SSLSockets require a supplied SSL Certificate?

In HTTPS technology, an SSL certificate is required for a secure connection. This certificate must be acquired through self-generation, or through a certificate authority (CA).
In Java, an SSLSocket to SSLSocket connection promises the same security as an HTTPS connection (No man-in-the-middle, encryption, etc).
When connecting two SSLSockets instantiated in two separate, stand-alone Java programs (One client, one server), is it necessary to supply Java (The server) with a valid certificate?
What are the methods used to specify which certificate to use? The documentation doesn't seem to have anything to say about this.
I'm talking about pure Java here. I'm not talking about using Java to connect to a web service via HTTPS.
The purpose of these sockets is to send user names and passwords from one Java application (The client) to another (The server) for identity verification purposes, so it is imperative that they are as secure as possible.
When connecting two SSLSockets instantiated in two separate, stand-alone Java programs (One client, one server), is it necessary to supply Java (The server) with a valid certificate?
In normal usage the server (the end with the SSLServerSocket) needs a certificate that is trusted by the peer.
The client only needs a certificate if the server is configured to require it, which is not the default.
What are the methods used to specify which certificate to use? The documentation doesn't seem to have anything to say about this.
See the JSSE Reference Guide. You can do this via system properties. You can also write a foot or so of code, but it isn't necessary.
If you want to have a secure encryption you need to have either a pre-shared key only known to both parties or you have to do some kind of key exchange to compute the encryption key. Key Exchange requires proper identification, otherwise a man-in-the-middle attack would be possible and you would not have secure end-to-end encryption anymore.
For use of pre-shared key look out for TLS-PSK. When googling for it it looks like that there are some hits for Android implementations but mostly it is people asking if it is possible. It might be possible to do this with the alternative SSL implementation BouncyCastle.
If not using PSK you might try to use anonymous ciphers (ADH). I don't know if they are supported by Java but in any case you would still need to have some kind of identification to make sure you are talking to the expected server.
And then there are of course certificates. You might use self-signed certificates together with public key pinning if you don't want to use public certificates for your application.
In HTTPS technology, an SSL certificate is required for a secure
connection. This certificate must be acquired through self-generation,
or through a certificate authority (CA). In Java, an SSLSocket to
SSLSocket connection promises the same security as an HTTPS connection
(No man-in-the-middle, encryption, etc).
No : HTTPS = HTTP traffic going through an SSL socket.
When connecting two SSLSockets instantiated in two separate,
stand-alone Java programs (One client, one server), is it necessary to
supply Java (The server) with a valid certificate?
Yes - Certificate and private key. If you want two way SSL, client would also need its own set of key/cert
What are the methods used to specify which certificate to use? The
documentation doesn't seem to have anything to say about this.
There's a lot of ground to cover. I'm not sure how much you already know, the things that you need to read up on include keytool, KeyStore, SSLContext, SSLServerSocketFactory, KeyManager.
Or you could directly go to examples like this

Java Server with Multiple SSL Certificate

I have a situation and not sure if it has possible solution.
I have a Java Server with SSL Socket and certificates "A" & "B". I also have 2 types of clients - one with certificate "A" and another with certificate "B". However only one certificate is loaded on a server side and therefore either clients with cert. "A" can connect or only clients with cert. "B" can connect.
Is it possible to modify Java Server such that up on a connection from any client, it will determine which certificate is used ( A vs. B ) and use appropriate cert?
P.S: Please pardon my security ignorance.
Thank you.
Being able to use two server certificates on the same IP address and port is possible via the Server Name Indication (SNI) extension, which must be supported by the client and the server.
Java supports this on the client side since Java 7.
Unfortunately, this is not supported on the server side yet. This is planned for Java 8.
Meanwhile, if you do need SNI support on your server, you may be able to use another server to handle the SSL/TLS connection and forward the plain text connection to your application. Typically, this can be done with Apache Httpd (with a reverse proxy) for HTTP(S).
Alternatively, it looks like the HTTPS-SNI-Proxy project may be more flexible for other protocols (despite having HTTPS in its name). I haven't tried it, but according to its README, it looks for the SNI extension in the initial Client Hello and then forwards the entire SSL/TLS connection (without deciphering it) to another server, depending on what is configured. In your example, you would have to set up two SSLServerSockets on distinct ports (not the one you really want to listen to) and forward connections from this tool to either port depending on what the client requests with its SNI extension.

How can I add encryption to my own TCP-based-Protocol using Java Sockets?

So, I have a working protocol that the Client needs to authenticate with user and password to login on the server. Then server and client would trade messages and files. It´s all working OK and I´m using Input/Output Stream for that.
I need to add encryption to the conversation and user/password authentication too. I dont want to store a symmetric key inside my jar, So I think I will need a public/private keys for that.
I know I could use the public/private encryption to send a symmetric key, but I really dont know how to do that in Java. And I think I could maybe just use encryption on the messages and not on file transfer.
I googled for it and found various ways of using cryptography with java sockets, whats the best(correct) way? Using CipherOutput(Input)Stream? Or is there another way?
If someone could post a piece of code I would be grateful
SSL. See javax.net.ssl and the JSSE Reference Guide.
If you are in a bind for time, you can piggy back on SSH port forwarding.
You will setup firewall rule on your server that would allow direct access to clear text port only from the firewall host.
Then on a client you will setup a port forwarding SSH session ( -L option on ssh client ).
The client machine then will talk clear text to a local host on the forwarded port and all conversation will be encrypted by SSH tunnel.

Java SSL sockets without authentication or stores?

I have two java applications that need to talk to each other over an encrypted TCP socket, but they don't need to authenticate each other (one will accept() a connection from the other). Can anyone point me to a tutorial/code-snippet that will help me set these up?
I'm looking for something fairly simple and I'd like to not have to supply any keystore or truststore material.
EDIT: I should be more specific here. I meant that they don't have to authenticate each other via SSL. I have some non-trivial authentication that I have to do at the application level, so I can't use any sort of SSL-based authentication scheme.
Also, some of the links in the answers posted so far (as of noon 3/10/2010) require keystore files. Is there a simple way I can programmatically generate the keys I need?
To reiterate Chris Jester-Young's advice - if you don't have authentication, then you might be communicating securely, but you have no idea who you're communicating securely with. You could simply be communicating very securely with the bad guy himself (who is relaying everything you're saying onto the person you hoped you were talking directly to).
However, there is a quite lightweight authentication scheme that might suit your purposes, called TOFU (Trust On First Use). This is where you use SSL and generate self-signed certificates for each side - however you do not skip certificate validation. Instead, on the first connection with a given peer you accept any certificate and store it locally; on subsequent connections with that peer, you only accept that saved certificate. This is similar to the way that ssh works by default for host authentication, and provides authentication of the "the guy I'm talking to now is the same guy I was talking to yesterday" variety.
You can use the anonymous Diffie-Hellman ciphersuites if you insist on ignoring Chris Jester-Young's sage advice. Those ciphersuites are not enabled by default, you have to explicitly enable them, for example by using the SSLSocket.setEnabledCipherSuites() method.
If you absolutely do not want to use SSL with certificates, you can roll your own, though it won't be as secure obviously. I'm just improvising here, mixing a little asymmetric crypto with port-knocking.
First, create a random RSA key pair in the client, in-memory, no need to store it anywhere. Client then connects to server using a plain Socket, and upon connection, sends the server the public key (encode as you wish, so that you can read it easily on the server). Server then generates a random 128-bit key, starts ANOTHER ServerSocket in a random port, and encrypts the 128-bit key and the new server port number, using the client's public key, and sends the data back to the client. Server must wait for a short period of time to receive a connection from the same client on the new port.
Client closes connection, deciphers data, and opens a new Socket to the server on the specified port. Then both client and server must wrap the socket's InputStream and OutputStream on a CipherInputStream and CipherOutputStream using AES/CBC/PKCS5Padding (or RC4 if you prefer) with the specified 128-bit key. Voilá, you have a secure connection between client and server, without any authentication.
If you want to handle authentication you can do so over the secure connection, or on the first connection the server can have RSA key pair as well, they exchange keys and the server can send a challenge to the client (the server sends the challenge to the client using the client's public key and the client responds to the challenge using the server's public key). But that's unnecessarily complicated and I think you'd be better off using standard SSL with keystores anyway... perhaps you can get create an in-memory KeyStore on the client and send it to the server as explained above using the first connection (encrypt the keystore with the server's public key) and then you can set up the second connection to use SSL with that keystore which is temporary and will be discarded when the client disconnects.

Categories