I have a client/server application that sends data over SSLSockets, so I generated a cert and loaded it with a trust store and keystore. The client is going to be public, so in order to work I need the client to have the javaTrustStore.jts file with it. Is it ok to bundle it in the resources directory? Or should I have the client generate a new key every time and add it to the server's keystore?
There are two ways that you can approach this.
The first is to have a certificate just on the server, and no certificate on the client.
The is the usual way that websites work - when the SSL connection is negotiated, the server sends it's certificate to the client, and the client verifies that the server cert is signed by a Certificate Authority that the client trusts. Most (all?) web browsers are pre-loaded with a number of certificate authoritys' "master certificates",
So, a Java application operating in this mode would need the "master CA certificate", and any "intermediate" signing certificates in it's trust store.
You can also be your own CA, which was done often in years past, when you had to pay for a server cert. These days, if you want a free cert, you can just use Let's Encrypt, or one of several other providers of free certificates.
If you need to validate the client when negotiating the SSL connection, then you would also put a certificate on the client. But, you can't just have the client generate it's own certificate. You'll need to have your CA generate and sign the certificate, and then give that to the client, who would need to add it to their keystore.
Again, in this case, you can act as your own CA, and generate "self-signed" certificates.
If you'd like to see an example of this, I wrote a blog post for my employer's web site about nine or ten years ago about doing this with an Android app.
Related
I've read a lot of articles regarding the import of a cert, but I am still unclear on a couple things.
When connecting to an SSL site from a Java application [in this case, a JBOSS web app], does the client cert need to be explicitly installed on the application server prior?
I can install a client cert manually, but there is an expiration date. So I'll need to manage the expiration dates of all client installed certs on our application server, and take an outage to update each one.
It feels like there should be a better way.
Shouldn't the application automatically accept a valid signed cert? [In this case, it is signed by VeriSign]
We are getting an exception currently when trying to access an https url from the application without explicitly installing the cert.
The API proxy library is swallowing the internal exception, so I dont know the details.
If the cert should be accepted automatically, then there may be a different issue here...
Can a signed certificate be used without importing explicitly?
Yes, it does not need to be installed prior to use. In fact, if you know in advance of what to expect, then you can include that information into the application. That has an added benefit of improving the application's security posture.
To avoid importing the certificate, use a custom X509TrustManager and override checkServerTrusted. In checkServerTrusted, ensure the server's public key is expected (i.e., pin the server's certificate or public key); or verify the server's certificate is valid (i.e., is within validity and forms a chain to your trusted root).
When connecting to an SSL site from a Java application [in this case, a JBOSS web app], does the client cert need to be explicitly installed on the application server prior?
In the case of client certificates, the server advertises the issuer whom it relies upon to issue client certificates. So the server will need to know the trust point for issuing client certifcates for authenticating clients.
In this case, it is signed by VeriSign
This could be really bad. In this case, you will trust all of your clients signed under the Verisign PKI, and all of Verisign's other clients signed under the Verisign PKI.
In this case, it would probably be better to avoid public CAs and run your own PKI (i.e., be your own CA). In this case, pick up a copy of Network Security with OpenSSL. The book will show you how to accomplish the customary tasks using both the openssl command and programmatically.
I saw that there were a few other Java and CAC posts on stackoverflow. I am a beginner with all of this stuff and I am still trying to a framework of what to do and where to go in my mind.
I am doing work for a big org that is using CACs with Windows 7 boxes to authenticate users who want to get into their PCs. They stick the CAC in their keyboard and type in a PIN.
My boss would like to alter our Java Webap such that it will not make the users authenticate if they have their CAC in their computer. If not, they will go through the traditional LDAP login.
We are using WebLogic 11g and Java 6.
From Googling around it seems like there are two approaches:
Implement an applet to read the user's CAC and send an SSL certificate to the webapp.
Implement "mutually SSL authentication" in the web server, which will cause the browser to send the SSL certificate on the CAC to the webapp
Do I have a correct appraisal of my options?
Which solution is easier?
Which will be less hassle, more robust in the long run?
I know next to nothing about SSL, which seems to be common in both solutions. I've found a few SSL tutorials that go on at length about abstract concepts. Can anyone recommend a good tutorial for what I want to do?
Thanks much in advance for any information or tips
Steve
Implement an applet to read the user's CAC and send an SSL certificate to the webapp.
Implement "mutually SSL authentication" in the web server, which will cause the browser to send the SSL certificate on the CAC to the webapp
You will want to do #2. You don't really want to have to mess with smart card hardware / software. Let the OS do all that work.
I've done this on IIS, but generically, to implement this, you will need to configure your web server to require client certificates and to trust the DoD CAs. You may need to configure your web server to advertise to clients which CAs it trusts. If the Win7 clients have a client cert that is signed by a CA you trust, the client will attempt to use it. If it's a smartcard certificate, Windows will automatically prompt the user for the pin; you don't have to worry about that. If the user types the correct pin, the cert will be sent to your web server which should then be able to validate the certificate with the CA. If it's a valid certificate, your software can then parse the fields in the certificate and use the values to help authenticate the user (ie whether, despite having a valid certificate, the user is actually allowed to login based on their name / email address/ etc). It's up to you how to handle it from there.
You will have a much easier time figuring this out and finding information if you forget that the users are using a smartcard or a CAC, and just start with the idea that you're going to use client certificates for authentication. Start by creating a self-signed CA test cert. Then create a server cert for your webserver and a client-certificate signed by your test CA. Add the test CA cert as trusted root cert on the client and the server. Then attempt to write a small test app that uses the client cert to authenticate to your webserver. Once you have that working, you can add the DoD CA and try to pull the info out of a CaC certificate.
good luck!
I have a Java CXF client that connects to a SSL secured Web Service with mutual authentication.
I have my keystore and my truststore properly configured on the client-side and it works fine.
I am concerned here by the fact that my keystore contains only one client certificate and on the CXF configuration it is not possible to say "ok for this SSL communication you'll use this certificate".
As I only have one certificate it's not difficult to choose the good one for CXF durign SSL handshake.
But this client will be deployed in a environment where it will be used with multiple possible client having their own certificate and each of them will be signed by the same certification authority. When the server will ask for a client certificate that is signed by a specific authority, there will be no way to distinguish one certificate from another.
How can I tell CXF (or Java) to use the proper certificate in this context?
Do I need to build as many SSL context as client certificates? (ie. having N keystore each of them containing only one certificate).
Or is there a way (in CXF conf or in Java) to say "use this certificate in this context"?
Thanks in advance for your help.
All the certificates must refer to the same client, otherwise the CAs are derelect in their duty. So they should all have for example the same subjectX500Principal. So why do you need a specific certificate? All of them identify the same client, so from an authentication point of view they are all equivalent.
It's starting to sound as though you want to use a particular certificate for authorization purposes, not just to establish identity via authentication. If so it is the wrong approach, a misuse of PKI. Authorization is an application-controlled step once you have an authenticated identity: get the identity of of the peer certificate and look up your authorization database to see if that identity is allowed to access this part of the application. Don't try to use a cacerts file as an authorization database, that's not what it's for.
I don't know if this is an option for you but I've done dynamic alias selection using WSIT before (i.e. one keystore, many private key entries). See this article for more detail. (Let me know if that article isn't enough - I can post more detail if you need)
I've generated a self-signed certificate for my Java app using keytool. However, when I go to the site in a browser it always pops up with a warning - saying this site does not own the certificate - is there a way to self-sign/doctor a certificate so I won't get these warnings in a browser? Both server and browser are located on the same host and I navigate to the site using "http://localhost/". I do not want to add an exception to the browser because I have tests which run on a big build farm so it is excessive to add an exception to all browsers on all build machines.
No, you can't. You might as well ask "How can I make a fake certificate for hsbc.com?"
There are two ways to get a browser to accept a certificate:
Buy a certificate for a domain from a trusted authority (which means proving to that authority that you own that domain) and then use that domain as the name of your test servers
Install your signing certificate into the browsers, so that you effectively become a trusted authority for that browser.
Without touching the browsers, there's no other way to do it - how could there be, if the internet is to remain secure?
You could also setup a self-signed Certificate Authority (CA) using OpenSSL or possibly your Java tool. You can then use that CA to sign a number of server certs.
You are still going to need to manually trust your self-signed CA on all clients that access your test servers, but at least you only have to trust one root CA, rather than a bunch of individual self-signed server certs.
Another option is to check out CAcert.
Is the certificate you created for localhost or for test.textbox.com? If you create a certificate for the FQDN test.textbox.com, that's how you need to be reaching the server to not get those errors, as long as the certificate is properly signed. You can't generate a certificate for the FQDN and then use an IP or an alias (localhost) to access it without being warned that things aren't matching up properly. Or am I misunderstanding your problem?
Make the certificate for "localhost" instead. It needs to match the hostname you have in the URL.
You will still be bothered as the certificate is not trusted, but that is another issue.
Is there a way for a java web app to get information on the security certificates installed on one's machine via a http request and selectively grant access if a particular certifiicate is installed on the machine.
Basically the requirement is, the web application should entertain request only from a company laptop else must deny access with appropriate error text.
(These could be win laptops with certain certifcates installed on their machine or they can be from a certain set of static ips.)
Yes, this is possible using HTTPS client certificates. The exact setup and configuration depends on your application server and specific requirements, but a common scenario woul be that you create a company internal CA (certification authority) to issue the client certificates which may be restricted to specific client IP addresses and configure your application server's HTTPS connector to require a client certificate and to trust certificates issued by your own CA.
After the proper configuration has been done, the client certificate(s) is/are made available to the web application through a servlet request attribute:
X509Certificate[] certificates = (X509Certificate[])
request.getAttribute("javax.servlet.request.X509Certificate");
As jambjo said - you can absolutely get client certificates through HTTPS with client authentication as he described. I'd recommend that over static IPs, a certificate is harder to spoof and allows more flexibilty if you need to reconfigure the network differently in the future.
A couple other thoughts:
Almost any application server will let you set a trusted certificate store - the list of CA certificates your application will accept for HTTPS client auth. Limit this to the CA that is providing client certificates - either an internal company CA or a certificate provider.
The choice of internal CA or CA provider is a corporate one. An internal CA will take manpower to set up and maintain, a CA provider will cost you money per certificate. There reaches a tradeoff point where it's cheaper to make the certificates yourself, but until you hit that point, the CA provider may be cheaper.
If you have an internal CA and your rule is that "any company machine (with a certificate) can access this application", then your work is done at the Trusted CA list in the applicaiton server, since you know the company CA will not be used for anyone but people in the company.
If you have a CA provider, you may need to limit your access control further and use the code jambjo provided to get the certificate and look at information within it. Typically, there is a organization (O) and organizational unit (OU) component within the subject DN (distinguished name) that will tell you what organization produced this certificate. You should be able to check that to be sure you have a company computer.
It's viable to do the O and OU checking if you know that your CA provider will never give out your company's O and OU names to anyone but a member of your company. If that is not the case, you may need to check against a back end data store (like an LDAP directory) to be sure the user or user's machine is known to you.
It's also possible to link the IP address of the machine to the certificate - often SubjectAltName (Subject Alternative Name) is used for this when the certificate is being constructed. I would not recommend it, because you will need a need a new certificate if you ever change the IP address of the machine. It seems unnecessarily complex for your purposes.