Jboss EAP 7 - Dynamic SSL authentication for REST API clients - java

I'm trying to get my head around some questions about SSL certificates and their signing.
My need : I need to be able to add (generate?) client certificate to allow them to use my API.
My problem : It seems that Wildfly needs to be reload if the java truststore is changed in order for the modifications to be available.
What I understood : This is a wrong approach of the problem and what should be done is the following:
Get a CA certificate from a trusted authority
Add this certificate to my keystore
Use that certificate to sign the clients certificates
This way only my CA certificate needs to be on my java keystores and through the CA validation chain, my client would be allowed on my service.
Questions :
Did I got this right ?
If I'm supposed to sign my clients certificates, what are they supposed to send me for the signing to be possible ?
Can this be done without calling keytool utility ? I'd like as possible can be to use java to do this and not rely on the OS.
If my CA certificate comes from a trusted authority and I use it to sign my clients certificates, those this still count as self-signed certificate ?
Thanks for all the pointers that you could provide.

Ok,
Since it may help others I'm going to put what my various testing helped me to figured out. :
Did I got this right ?
As far as I can tell : Yes
Why can't I be sure about it ? Because I'm encountering some testing limitations due to my development environment and the fact that I can't have a real valid certificate with a valid domain to test it.
If I'm supposed to sign my clients certificates, what are they supposed to send me for the signing to be possible ?
So what they need to send for the signing to be possible is a CSR (Certificate Signing Request) and their public key.
Can this be done without calling keytool utility ? I'd like as possible can be to use java to do this and not rely on the OS.
This should be doable using the Bouncycastle library. I'm using should because I did not go into implementing it, more on tha later.
If my CA certificate comes from a trusted authority and I use it to sign my clients certificates, those this still count as self-signed certificate ?
I'm still not clear on that, but it seems that there is some kind of scope on certificate signing that prevents anyone from faking the actual CA. Anyone that can put more sure knowledge on this, is welcome.
What I actually ended up doing :
Being our own CA would be too much hurdle, so what we're actually going to do is ask our clients to get their certificates from known CA and add those CA certs to our truststore. This is the same principle as before but instead of us playing at being CA, we'll leverage actual CA sources.
Hope this helps anyone that would some kind of equivalent requirement.

Related

Use CA certificate my own code

I have searched on several topic but I don't really find what I need. The problem is : I'd like to sign file with digital certificate from my own writted program (desktop or web). Then I want to know:
If I can do that with CA certificate.
Which CA can issue me certificate I can use in my program. I mean CA certificate file with method to access to Algorithm, Key, and also to send verification request to server? A kind of API?
Does this kind of certificate exist ? Can I found it for free?
For as long as I understood your questions correctly, find below my answers:
1 - You can generate get you Digital Certificate by generating you key pair and then sign your public key by any CA (either your own CA or any Publicly trusted CA)
2 - You can make a request to a CA to get your Digital Certificate. Guessing that you want a publicly trusted certificate than you can use a wide range of CA's. I would suggest you to check the Let's Encrypt project, they release free certificates.
Using your digital certificate is a matter of your implementation. Basically you need to know what do you want to achieve with it (like confidentiality, authentication, integrity..). Usually you want to implement SSL to achieve any of these features.
For signing documents you need to encrypt with your private key associated with the public key that was used to get the digital certificate.
3 - As I also stated in the second answer, Yes there are free options for publicly trusted digital certificates

Can a signed certificate be used without importing explicitly?

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.

Error: Not trusted server certificate on Android 2.3 and older

I have certificate from GlobalSign.com ( .pem file). This file consists of 2 certificates inside (I've examined it with Portecle). Using Portecle I created BKS keystore and tried to use it in the app. I have read many different tutorials with similar topic. I've tried:
Security with HTTPS and SSL
One more solution
Using a Custom Certificate Trust Store on Android
Android: Trusting SSL certificates
others
Any solution didn't work, and I still have "Error: Not trusted server certificate". Maybe You have any idea what I'm doing wrong.
P.S. There are a lot of trust-all 'solutions', but I need proper solution
It is difficult to say exactly why you are having the issue but it sounds like you do not have the private key, the certificate you received from GlobalSign, I presume you generated the CSR? If so you will need to import the .pem file that you received back from GlobalSign the same method, if you did not generate the CSR from a private key within you BKS keystone then it would not be a trusted certificate.
That is what I think is going on anyway
Problem was solved. I have asked technical support of GlobalSign about certificates. They made some tests and took recommendations how to configure certificates on server side. Android part wasn't changed

SSL "Peer Not Authenticated" error with HttpClient 4.1

I am building a simple app monitor to poll one of our API URLs and email us if it can't get a HTTP 200 status code from the response (this would indicate our API is down for some reason).
I am using HttpClient 4.1 (this is important because its API differs greatly from 3.x).
Our API is secure with SSL, however entering:
http://example.com/our-api
into a web browser redirects you to
https://example.com/our-api
Without causing any errors.
When HttpClient attempts to hit this URL (http://example.com/our-api), it fails with a javax.net.ssl.SSLPeerUnverifiedException exception with a message stating:
peer not authenticated
I see this happening a lot for other people as is evidenced by this post (which also provides some ways of circumventing this problem - a solution that I am going to try and implement tonight in fact).
What this other post (and the other similar ones to it) do not do is explain why this is happening in the first place! So, rather than ask "how do I fix this?" I figured I would ask "why is this happening?" Before I go barging ahead with one of the proposed solutions, I'd like to know what the problem is that I'm attempting to fix ;-)
If the server's certificate is self-signed, then this is working as designed and you will have to import the server's certificate into your keystore.
Assuming the server certificate is signed by a well-known CA, this is happening because the set of CA certificates available to a modern browser is much larger than the limited set that is shipped with the JDK/JRE.
The EasySSL solution given in one of the posts you mention just buries the error, and you won't know if the server has a valid certificate.
You must import the proper Root CA into your keystore to validate the certificate. There's a reason you can't get around this with the stock SSL code, and that's to prevent you from writing programs that behave as if they are secure but are not.
This is thrown when
... the peer was not able to identify itself (for example; no
certificate, the particular cipher suite being used does not support
authentication, or no peer authentication was established during SSL
handshaking) this exception is thrown.
Probably the cause of this exception (where is the stacktrace) will show you why this exception is thrown. Most likely the default keystore shipped with Java does not contain (and trust) the root certificate of the TTP that is being used.
The answer is to retrieve the root certificate (e.g. from your browsers SSL connection), import it into the cacerts file and trust it using keytool which is shipped by the Java JDK. Otherwise you will have to assign another trust store programmatically.
keytool -import -v -alias cacerts -keystore cacerts.jks -storepass changeit -file C:\cacerts.cer
Im not a java developer but was using a java app to test a RESTful API. In order for me to fix the error I had to install the intermediate certificates in the webserver in order to make the error go away. I was using lighttpd, the original certificate was installed on an IIS server. Hope it helps. These were the certificates I had missing on the server.
CA.crt
UTNAddTrustServer_CA.crt
AddTrustExternalCARoot.crt

A straight forward way to open self-signed HTTPS SSL URLs in java?

I'm building an application that needs to open self-signed HTTPS SSL URLs in java. I've learned that you can bypass the SSL problems by adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where you say what hostnames are allowed.
However, I have a second problem where my servers are running self-signed certs. So even with the hostname bypass I'm getting exceptions like:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I've looked around and the only solutions I've found is to add the certificate to the java key store, but this is a problem for me because I have no control over when or how they update java, and I've read that the keystore isn't preserved between updates, and I have no access to the system outside of the JVM.
My application will only make calls to a single server so if there was a way to bypass the self-signed restrictions, and never consult keystores, it wouldn't be a security problem, but is there a way to do this?
I'm building an application that needs to open self-signed HTTPS SSL
URLs in java. I've learned that you can bypass the SSL problems by
adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where
you say what hostnames are allowed.
There are some misconceptions from your question:
Hostname verification is unrelated to whether the certificate is self-signed or not.
It is a verification that matches the domain you are trying to access with the certificate info (CN or Subject Alt Name).
You would need to configure the verifier if you needed to accept a certificate that did not match the url (not recommended at all!!!)
Concerning the self-signed.
This is irrelevant.
You can configure your application to load your custom truststore which would include the certificate your application will trust. In fact this is the best approach (than using Java's cacerts).
All you have to do is import the certificate in a keystore (JKS or PKCS12) and load it in your custom TrustManagers in your application.
Just google arround, plenty of examples E.g. self-signed-ssl
As much as I hate to say this, sometimes it's better to just go with the flow.
Java is attempting to make applications more secure through the use of proper SSL verification practices. In this case, it is succeeding: had you been able to tell the program "it's okay, accept the untrusted self-signed certificate", your program would have been vulnerable to a man-in-the-middle attack where Mallory puts his server (with its own self-signed certificate, just as valid as yours!) in between the host and the target it's attempting to communicate with. Then he proceeds to read all the traffic you thought was nice and safe, and you don't even notice.
So, your assertion that telling Java to "trust any self-signed certificate when connecting to this host" is secure is, regrettably, not correct.
You can get free, totally valid SSL certificates from StartSSL. They're good folks.
That's how PKI is supposed to work - you must have complete chain of trust from some trusted certificate stored in you keystore to your certificate. So you can
set you certificate as trusted
ask somebody already trusted (i.e. with trusted certificate in the keystore) to sign you certificate
Trying to bypass that is not good bad idea. You can install you certificate in some Java post-install hook, you may have some cron job checking it periodically or do it in exception handling. You can even download this way a certificate from the server and install it everytime it changes (extracting the cert with openssl is easy). But for god's sake, if you decide to do such thing, at least write some audit log about it to some third machine a make sure somebody reads it.
You can also write "hacker-friendly" on you doors. :)
(Note that when you're talking about "keystore" in your question, you're in fact talking about the trust store (which is a keystore). More details on this unfortunately confusing Java terminology are in this answer.)
My application will only make calls to a single server so if there was
a way to bypass the self-signed restrictions, and never consult
keystores, it wouldn't be a security problem, but is there a way to do
this?
Actually, it would be a security problem. Your application may indeed be intended to call only a single server, but the trust store is precisely there to help make sure you're connecting to the machine you intended to connect to. Without it, you wouldn't be able to know whether you're connecting to that server or a MITM server.
If you want the security provided by SSL/TLS, don't bypass these rules. (In particular, don't use a trust manager that will accept any certificate.)
I've looked around and the only solutions I've found is to add the
certificate to the java key store, but this is a problem for me
because I have no control over when or how they update java, and I've
read that the keystore isn't preserved between updates, and I have no
access to the system outside of the JVM.
Quoting myself from this answer (to a more specific question):
The right way is to import this self-signed certificate into the client's trust store, using keytool for example:
keytool -import -file server-cert.pem -alias myserver -keystore mytruststore.jks
You can either do it directly in the JRE's trust store (lib/security/cacerts), which may lack some flexibility, or do it in your own copy of this file, which you then set as the trust store (the default password is changeit or changeme on OSX). You configure this truststore globally for your application using the usual javax.net.ssl.trustStore* system properties (e.g. -Djavax.net.ssl.trustStore=mytruststore system property (and -Djavax.net.ssl.trustStorePassword`). [...]
You don't actually have to use the trust store provided by the JRE (and which may be updated regularly). You could import your self-signed cert into a new empty keystore, which you'll use as a trust store within your application (don't import the private key with it). How to discuss trust store management was in fact discussed in this question: nothing prevents you from using a different trust store specifically for your application or part of it (and in fact Sun/Oracle make no guarantee as to the suitability of the default trust store).
I'm building an application that needs to open self-signed HTTPS SSL
URLs in java. I've learned that you can bypass the SSL problems by
adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where
you say what hostnames are allowed.
While it may indeed by slightly less of a problem if you only have a single self-certificate in your trust store, host name verification is also an essential component of the security provided by SSL/TLS. Don't bypass it, verify that the certificate you're connecting to matches the name you're trying to connect to. (To make an analogy, if you want to check someone's identity, you not only want to check the their passport was emitted by a country whose passports you trust, but you'll also want to check they have the right name inside, otherwise you could be in front of anyone from that country.)
Making the CN= RDN of the Subject Distinguished Name of your self-signed certificate be the host name of the server should be enough, although it's the legacy way of doing it. You may also want to add the Subject Alternative Name extension. More on this in this answer.
Generally speaking do not bypass the SSL "problems". These mechanisms are precisely in place to make the usage of SSL/TLS secure.

Categories