Handling self-signed SSL certificates in Java - 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.

Related

Configure additional truststore in Spring Boot Tomcat Server

I have a spring boot client application and a server application. I am implementing MTLS client authentication part. I have a client certificate that is self signed and this needs to be added to a custom truststore in the server. Basically I am looking for a mechanism to add my custom truststore at runtime.
I want the default truststore and the custom truststore to be picked up. I implemented this using TomcatServletWebServerFactory but I did not have any luck. Can someone please help. I am looking for a programmatic solution.
I do not want to change the default java truststore. I still need that.
Since you do not want to replace the existing truststore with your custom one (that could be done by running the JVM with a few system properties) you need to add code that trusts a peer if the builtin or a custom trusttore approve the client.
For this you need to create and install your own Trustmanager. See an example here: https://community.oracle.com/tech/developers/discussion/1535342/java-ssl-trustmanager
If the checkClientTrusted and checkServerTrusted methods do not raise an exception the certificate is approved. Leaving the methods empty would even turn off any certificate validation - not to be recommended.
In order to establish a SSL connection with client certificates between a Spring client application and a Spring server application, there are a few things to note:
Involved Trust Stores
There are two very different trust stores relevant in this context:
The trust store used by the client to determine whether it can trust the server's SSL certificate. When using the java.net package for client requests, the trust store is configured via the JVM property "javax.net.ssl.trustStore" - see e.g. https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html
The trust store used by Tomcat (the underlying servlet container used by Spring Boot in its default configuration) to determine whether it shall trust a client. This is configured via the spring application property "server.ssl.trust-store" - see https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.server.server.ssl.trust-store
In the context of a Spring server application the first one is relevant for connections which the server makes to a second server - so only when the server acts as client as well - e.g. when acting as a proxy server.
The second trust store is relevant for connections between the server and its clients. This is the one you need to deal with.
Certificates in the Tomcat Trust Store
The trust store which is used by Tomcat does NOT contain the client certificates. Instead, it must contain the certificate of the Certificate Authority who has signed the client certificate. So when using self-signed certificates, you need to install the CA certificate which you have generated on your own.
The big advantage of this is, that you do not need to change the server trust store, when you grant access to new clients.
The downside is, that you have to handle a certificate revocation. The CRL (certificate revocation list) is also stored in the trust store. See:
CRL Explained: What Is a Certificate Revocation List?
Merging the Default Trust Store and the Custom Trust Store
As now should be clear, this is not a good idea and would constitute a major security flaw, as it would allow any client which has a certificate signed by a CA in the default trust store (which can be easily obtained) to connect to the server. The server trust store must only contain those certificates which you use to sign your client certificates!
And there is no need to merge the two, as this are totally separate trust stores with totally different functions.
But, of course it is technically feasible to merge trust stores. This can all be done by keytool - see below.
Managing Trust Stores
Adding, deleting, exporting, listing, and printing certificates and CRLs can all be done via the Oracle command line tool "keytool", which is part of the OpenJDK. See
keytool Reference

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'.)

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.

Calling Https Url

I have written web service and hosted project on server with SSL certificate.If I want to call HTTPS url, I need to import certificate in JVM manually or through program on client side.
I can't ask any client to do extra work on his side before calling my https url, I would loose my credibility.
If any one knows how to deal with this, please help me on this.
Ideally, you should pay for a real SSL certificate (trusted by one of the common root certificate authorities), rather than getting a self-signed one. Then there won't be any need to important any certificates.
The point about losing credibility with your client is an important one, because that's precisely why you need to buy an SSL certificate - it establishes that an element (however weak) of authenticity... you might still be serving up malware or whatever, but there's still a paper trail back from the site serving the content to whoever paid for the SSL certificate.

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