Java SSL Certificate - java

I need to communicate between two desktop Java app, and the best way to do this is to use SSL (to prevent sniffers). I control both the client and server so self-signed is okay.
My question is if a certificate can be made and used from scratch programmatically (i.e. the end user does not have to physically do anything himself).
If this is possible, could you give me some pointers?

My question is if a certificate can be made and used from scratch
programmatically (i.e. the end user does not have to physically do
anything himself).
Before you think of generating certificates (programmatically or not), you need to decide how you're going to verify them. In the context of two desktop applications, the traditional way of verifying a server certificate might not be suitable.
The purpose of the certificates is to give a way to verify the identity of the remote party, so as to prevent Man-In-The-Middle attacks. The verifying party uses something it already trusts to make this verification; not doing so makes using certificates pointless.
In the traditional model (with a fixed server), the server certificate is part of a PKI and issued by a CA. The client verifies its authenticity against a set of CA certificates it trusts (typically using the rules described in RFC 5280, and it verifies the certificate is valid for the host name is was looking for (how this is done depends on the protocol, but best and historical practices are described in RFC 6125). Both steps are necessary to prevent MITM attacks. It's similar to verifying someone's identity using a passport: you want to check that the passport is real and from an authority you trust, and you want to check that the name (or picture) matches the name you're looking for (or the face in front of you).
When establishing a communication between two desktop applications, you're certainly going to have problems with both aspects: how to let the client verify the cert was issued by an entity you trust, and was issued to the entity you want to communicate with. If you generate the certificate programmatically no either side, it's certainly going to be self-signed, which will make verifying its authenticity from the other side difficult without another means of exchange (independent of this SSL/TLS communication). In addition, desktops tend not to have fixed host names, so a DNS-based (or even an IP address) identifier might be inadequate in this context.
You'll need to think of a way to publish the certificate in a way that the remote party can verify it trusts it, and to think of an identifying scheme to make sure the certificate belongs to the right entity (this is typically what goes in the Subject DN or Subject Alternative Name extension of the certificate).
Once you've made these decisions, you can use BouncyCastle's org.bouncycastle.x509.X509V3CertificateGenerator to generate your certificate (an X.509 v3 certificate should let you add extensions to the certificate, e.g. for key usage purpose, if you need them). There are various examples (for v1, v3 and/or self-signed, i.e. where Subject = Issuer) on the BouncyCastle wiki. I'd say that using this is the easy bit unfortunately (the administrative side of trust would be the hardest).
If both desktop applications are in fact both part of a more central application, you could run a service that issues this certificate, from a certificate request (CSR) generated within your application. A central server would effectively run your own CA, and your desktop applications would trust that CA. Depending on the complexity of your organisation, there are tools available to do this, or you could also use BouncyCastle to implement it, using the same classes (it would even be better if you implemented CRL/OSCP to be able to revoke certificates). In this case, you could make your application generate a CSR and submit it to your central CA. CSRs can be generated with BouncyCastle using PKCS10CertificationRequest. Again, how your CA verify the CSR comes from the right party, using external information, is also an administrative problem, perhaps you can tie it to an e-mail verification scheme or something like that.
Once you've generated your certificates, you'll be able to use Java's JSSE as your SSL/TLS stack (typically using SSLSocket). You may have to use custom X509TrustManagers to implement the certificate verification (depending on how you've designed your scheme to verify the certificate, if you're unable to use a traditional CA model). Just make sure you don't use trust managers that don't do anything in their check* methods; there are a number of examples of this around: you might as well not use certificates at all in this case, if you don't do anything to verify them (this would make the connections vulnerable to MITM attacks).

You could use a JCE based solution with SSLSocket, docs for jdk6 and its implementation: SSLSocketImpl.
Java SSL SSH:
You have Jsch lib to connect to any server with SSH protocol.
Java Toolbox for SSL:
You have Bouncy Castle.
Look at their resources and their documentation. The wiki provides some usefull examples with the latest releases:
ContentSigner sigGen = ...;
PublicKey publicKey = ....;
Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);
X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
new X500Principal("CN=Test"),
BigInteger.ONE,
startDate, endDate,
new X500Principal("CN=Test"),
publicKey);
X509CertificateHolder certHolder = v1CertGen.build(sigGen);

Related

Handling self-signed SSL certificates in Java

This previous question dealt with the handling of self-signed certificates in Java:
Accept server's self-signed ssl certificate in Java client
The accepted answer offers 2 possible options: (1) manually load the relevant certificate into the local keystore (2) circumvent UrlConnection's security with a bespoke TrustManager
In the context of a web crawler whose function is solely to extract content from remote https secured sites, what specific risks arise from option 2.
And, assuming those risks are deemed unacceptable, what alternative exists since it is not viable to manually extract the certificates and load into the local keystore.
Not only from option 2 but also from 1, the only risk is that there is no guarantee that the server your webcrawler is crawling is effectively the one you think it is. There are other risks but are not associated with the tasks a web crawler does.
For your second question: You need to identify why it is unnaceptable, because it is very easy to code in java to just accept the self-signed certificate. What specifically blocks you to code to accept the certificate? You can use a proxy server to automatically accept all certificates but this is a separate topic and it would be better to create a new question for it.

Creating an ephemeral SSL / TLS socket using a fresh key pair

Every tutorial I have found explains how to create an SSL/TLS connection with SSLSockets using a keystore file and truststore to store an SSL certificate after creating it manually with the keytool utility.
I would love to know how to do the same thing but with a public key/certificate generated on the fly (ephemeral).
It's so easy to create an RSA/EC key pair in Java so why can't we just use it for an SSLSocket as well? This has two big advantages in my opinion: it allows for forward secrecy and at the same time I don't have to deal with passwords, utilities, file readers and keystore converters for Android.
This has two big advantages in my opinion: it allows for forward secrecy
Forward secrecy typically deals with the key agreement like ECDHE or DHE (though the latter is now widely deprecated due to logjam).
It is good practice to re-key certificates from time to time, though a new one for every TLS session is not necessary.
It's so easy to create an RSA/EC key pair in Java so why can't we just use it for an SSLSocket as well?
You need an X509 certificate too, not a just a key. You can still make those on the fly, but you are going to have to sign the certificate. Either the certificate will be self signed, or you need a certificate authority that can sign certificates very quickly, on demand. Practically, the latter doesn't exist and would mean very slow handshakes.
If the certificate is self-signed, browsers or any other user agent will not know how to trust the certificate, and using a self signed certificates severely impacts the use of TLS.
As a technically correct but fairly useless alternative:
TLS actually defines 'anonymous' keyexchange methods DH_anon and ECDH_anon (and ciphersuites using them) which do forward-secret key agreement using ephemeral keypairs, and NO authentication, thus not requiring any certificate or keystore on the server or (potentially) truststore on the client.
Being unauthenticated, they are easily vulnerable to active attack, and thus people (and authorities) who actually want security consider them unacceptable for use. Java (JSSE) does implement them, but does not enable them by default; your code must call .setEnabledCiphers with an appropriately modified or set list. Most other SSL/TLS implementations either similarly disable them or don't implement them at all.
But technically that is a valid way to do TLS with no long-term keys and certs, and thus no manual effort for adminstering them.
As an aside, I believe this is why creating an (SSLContext and) SSLSocketFactory with (KeyManager for) a keystore not containg a valid privateKeyEntry does not give an error, because in principle it could create sockets (or engines) used for anonymous connections. Instead, since in practice anonymous keyexchange is never used, these factories cause all subsequent connections to fail in a fashion many nonexpert programmers have trouble diagnosing. (In contrast trying to create a validator for an empty truststore throws a specific exception, something like 'trust anchor set must not be empty'.)

Is it sensible to use a public and private key encryption between a client server model?

My plan to make my server harder to emulate goes as follows;
The client creates a random string, String random;
This string is then encrypted and sent to the server. The server then decrypts it and sends it back, if the one sent back is the same as random, then they are connected to the right server (and not a fake one with a diff private key).
How can I make it so that each client has the public key and the server holds the private key? Not a clue.
EDIT -
Because I do not want the clients to have to have extra files for the public key, can I allow them to download the public key on runtime? If I hold it on the server and like serialize it? How?
Is it sensible to use a public and private key encryption between a
client server model?
In a word? No. At least not the way you describe it.
You could get this to work as described, but you will have created security theater rather than effective security.
If you use public/private key pairs that are not bound to certificates, you have a key exchange problem. As noted in the comments, if the app just downloads the key from the server to which it connects, and that key is not in a certificate, there's no way to tell it's authentic to the intended server.
If you use public-/private keys bound to certificates it solves your key exchange problem since you can download the cert from the target server and inspect the Subject Distinguished Name and Issuer Distinguished Name to discover whether the public key you have is authentic. But once you have gone to the trouble of deploying certificates, just use TLS. It's there, it's reliable, and most importantly it's been thoroughly hammered at and known bugs fixed so its as trustworthy as we have available. Your home-grown protocol is not.
What you are describing can be achieved with other standard protocols such as Challenge-Handshake Authentication Protocol (CHAP). If TLS doesn't meet your requirement, use a standard protocol. Even an old deprecated one would be better than writing your own because, like TLS, it's been hammered on extensively in the real world.
Assuming that you did implement the protocol proposed, then what? Authenticate then communicate in plaintext? Why expend more effort than implementing TLS, to deploy something far less secure than TLS, that doesn't even provide privacy or integrity of transmitted data?
Because I do not want the clients to have to have extra files for the
public key, can I allow them to download the public key on runtime? If
I hold it on the server and like serialize it? How?
If you use CA signed certificates (from an internal or external CA) you can dynamically fetch the certificates from the target server. The only thing you need to store is the signer chain in your Trust Store and the acceptable values for Subject Distinguished Name and Issuer Distinguished Name. The remote cert won't validate if the signer certs are not in the Trust Store so a man in the middle can't just swap out any cert with the right distinguished names. Once it validates to your Trust Store, your inspection of the distinguished names determines if you have the right cert and server.
Finally, the question doesn't mention revocation at all. If you use CA-signed certs from a commercial CA or from an internal CA that is at least somewhat robust, you can check at run time against a Certificate Revocation List or use Online Certificate Status Protocol. Again, these are built into the TLS protocol as implemented in any JSSE standard provider.

X.509 certificates for authentication without using client SSL

I'm trying to improve some code that enables logging in to our application using digital certificates, probably certificates stored on PKCS11 tokens.
It's a Java client server application, with the server on JBoss [Wildfly], and a rich Java thick client. We also have a GWT/Javascript based web client, but this doesn't yet support certificate auth.
The current implementation uses 2-way SSL authentication if certificate authentication is configured, i.e. the server will require a client certificate when the connection is opened. This causes some problems, and in trying to find ways to address them I've been searching madly to see if there is a standard, 'Right Way To Do PKI Auth To A JBoss Application'.
However just about everything I have found on the subject seems also to revolve around using two-way SSL, which kind of implies that is the Right Way to Do It.
It seems undesirable to me, in that the network transport is quite a low-level concern, heavily separated from the application logic and stuff like authentication and user management.
In order to prove the client is a valid user of the system (as opposed to merely someone with credentials endorsed by a CA in the server trust store), the server application logic has to rummage around looking to find the certificate that was used on the incoming connection in order to scrape the Common Name off it. I've discovered that javax.servlet.request.X509Certificate is a standard-ish parameter one can query on the servlet, so it ought at least to be possible.
The other architectural problem this causes is that our app requires reauthentication for the lifetime of certain sensitive operations. If one is using the SSL connection to prove the user has the private key, then logically that would require opening a whole separate connection.
Logically, authenticating with a certificate would seem to require
The server generating a nonce
The client encrypting the nonce using the client's private key
The client sending that encrypted value to the server with the accompanying public certificate [or certificate chain].
Now, that is exactly what happens during an SSL handshake, but obviously a whole load of other baggage comes with it that is irrelevant to the application-level concern of authenticating the user.
I thought about implementing the steps directly myself, but this would seem to violate the first rule of crypto (Don't implement your own crypto).
If the server generates random nonces then that introduces a level of chattiness and statefulness to the process, which is doable but a pain when you are striving for a stateless and clusterable server.
Time-based One-Time Password implementations circumvent this, and seem to be a standardized mechanism for 2-factor authentication that is getting support from Google+ and the like.
However I can't find anything in the way of out-of-the-box libraries that will let me build an implementation using certificates directly from an imposed PKI.

SSL and Tomcat using Java

I'm new to SSL connections so here goes my question.
I have a desktop Java program in a JAR file. This JAR sends sensitive information over the internet to a remote Tomcat server. Of course I need to encrypt the data.
If I purchase an SSL cerfiticate say from Verisign, will the data sent over SSL be automatically encrypted?
I mean in my JAR, will I still need to do extra work like use Java encryption extensions API to manually encrypt my data over the SSL connection?
Thank you.
I mean in my JAR, will I still need to do extra work like use Java encryption extensions API to manually encrypt my data over the SSL connection?
Encryption will be done for you (with the Java Secure Socket Extension). Just establish your connection using https://. Maybe have a look at HTTP Client for a higher level API.
By the way, the certificate goes on the server side (unless you want to do client-authentication too in which case, well, you'll need a client certificate too).
And yes, you could use a self-signed certificate but one of the benefits of using a certificate signed by a well known Certificate Authority (CA) like Verisign, Thawte, etc is that you won't have to add it to the trust store of the client VM (unless you disable the verification mechanism).
Follow the SSL Configuration HOW-TO on how to setup https.
If your goal is just to get the encryptian, you don't need to buy a certificate. You can make your own. Buying a certificate just creates the verification chain back to verisign (or whomever) to give users a warm fuzzy that you're really who you say you are.
SSLSocket should handle most of the work for you.
All data sent over SSL is by definition encrypted, you do not need to worry about encryption at all. Also, you do not need to by a certificate to achieve that: you can issue one on your own.
If you'll set up the SSL on Tomcat and send your data over HTTPS then the encryption will be done for you. But you don't actually need to purchase a certificate if you only need encryption for your data channel, you could generate a self-signed certificate. Have a look at this page http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html on how to configure SSL for Tomcat. But note that HTTPS can be configured not to use encryption at all (at least on Apache httpd).
To answer your question, SSL implementations automatically encrypt the data. You don't need to worry about using additional encryption routines.
It might be easiest to purchase an SSL certificate because SSL implementations provide easy certification authentication using common root certificates and provide a verification service. However, you could save some money by using a self-signed certificate.
Even with a self-signed certificate, it's important to validate the signature on the server certificate from the desktop application when you connect to the server. This will prevent man in the middle attacks.
You won't have to add your self signed certificate to the store because you should be able to disable the automatic verification mechanism and use your own.

Categories

Resources