Behavior of HttpURLConnection for URL with Revoked SSL Certificate? - java

We're going to have a bumper crop of revoked SSL certificates, courtesy of heartbleed. When I saw that Chrome on Android apparently ignores revoked SSL certificates, I wondered what the behavior would be when requesting in Java a Web resource from a server, where we get a revoked SSL certificate.
What I hoped for was a crash with some sort of SSLHandshakeException.
What I am seeing is a successful connection, but downloading no data -- reading from getInputStream() returns a length of -1. This is tested using https://revoked.grc.com/ as my test site, which will return an explanatory page if you download it ignoring certificate errors (e.g., via wget -no-check-certificate). I have tried 4.4, 4.3, and 2.3 emulators, with the same results.
Is there a specified behavior for the Java VM? I doubt that there is an Android-specific specification, but if Android's actual behavior differs from a Java specification, I can work to get the differences clarified as either being bugs or missing documentation.

The expected behavior would be for X509TrustManager to catch a CertPathValidatorException from CertPathValidator and re-throw it as a CertificateException (a CertificateRevokedException when available in Android).
CRL checking is disabled here, on line 362. Note that its not as easy as removing that line, since if a cert has no CRL, a CertPathValidatorException is also thrown.
CertPathValidator is implemented here and as far as I can tell, by wandering through the source, it doesn't download the CRL's.

This is based on a cursory reading of the javadocs and the JSSE Reference Guide for Java.
The javadoc does not say what happens in the way of SSL certificate verification. On the contrary, the APIs make it clear that the whole process is highly customizable, starting with a SSL socket factory and/or a HostnameVerifier. The javadocs do not say anything about the behaviour of the defaults.
The JSSE reference goes into a lot more detail, but it is also very complicated ... and clearly JSSE implementation specific. But I think it says that this stuff is handled by the trustmanager, and the default trustmanager is PXIX. Then it says the following:
"If the init(KeyStore ks) method is used, default PKIXParameters are used with the exception that revocation checking is disabled. It can be enabled by setting the system property com.sun.net.ssl.checkRevocation to true. Note that this setting requires that the CertPath implementation can locate revocation information by itself. The PKIX implementation in the SUN provider can do this in many cases but requires that the system property com.sun.security.enableCRLDP be set to true."
In short, certificate revocation checking is disabled by default.
I haven't researched the Android case, and I would not expect the Android implementation to be the same.

Related

How to access a valid Oracle page through https with Jersey client?

I have been surprised to observe that the code ClientBuilder.newBuilder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build().target("https://www.oracle.com/java/technologies/naming-conventions.html").request().get(); throws a “Read timed out” exception using the Jersey JAX-RS client implementation. (When I tried to report this, I was told that it is not a bug.)
I expected that Jersey would use the default Java truststore, and that the default Java truststore would include CA certificates that permit to trust Oracle’s (and many other) website.
Indeed, running keytool -list -cacerts, I see that my truststore contains 166 certificates. I suppose that some of them permit to validate Oracle’s website, but I do not know how I can check that (well, apart from doing exactly what I am trying to do with Jersey).
I realize that I can download Oracle’s certificate and add it to my truststore, but I obviously do not want to do this for every classical web site out there to which I would like to connect using SSL. I would rather like to understand which web sites are supposed to be trusted by default in a “normal” Java installation (is there an official documentation about this somewhere?); how I can check whether my specific installation has some problem that prevents Oracle’s web site to be trusted; or, if it is normal, whether I can tell Java once and for all to trust the web sites that, say, Firefox or Chromium would trust by default.
This answer, for example, suggests that OpenJdk (which is what I use) should trust by default the same web sites as Firefox. And Firefox obviously trusts Oracle.
What am I missing?
Edit I realize it seems relevant to specify that I use Debian stable, as this issue might be OS-specific. I wonder if there’s something going wrong on my installation. “As far as I'm aware every distro patches OpenJDK to use its own list, which I guess is why this issue hasn't got much attention on GNU/Linux systems” -- Andrew Haley on OpenJDK ML. “Debian has tooling to create a cacert file from the system‘s keystore. There is a hook system that updates the cacert every time the system‘s keystore is changed. lib/security/cacert is actually a symlink to that file. (…) In case of Debian, it‘s identical with Mozilla‘s list.” -- aahlenst on GH Adoptium issue. Indeed: ls -l /usr/lib/jvm/default-java/lib/security/cacerts reveals that it links to
/etc/ssl/certs/java/cacerts.

How to disable common name check in SSLContext in java?

I am using SSLContext so set up Jersey client, and need to disable the common name check in order to avoid unnecessary issues. However, I can find no documentation as to how we can do it correctly. So is the common name check disabled by default in SSLContext (assuming using TLS) or do we need to explicitly disable it? If so, how? Thanks.
This does not answer your question, but it tells you that what you are doing is a bad idea and probably caused by a misunderstanding of how verification works.
...need to disable the common name check in order to avoid unnecessary issues
I don't know what the "unnecessary issues" are which you are trying to avoid, but not verifying the hostname is more or less that same as disabling all validation and thus make it possible to incorporate the server and/or to do man-in-the-middle attacks.
If you don't verify the hostname but still validate the certificate trust chain the attacker can now simply use a certificate signed by a trusted CA for the attackers own site, e.g. attacker.example.com. CA's will issue such certificate since the attacker can prove ownership of its own site.
Using its own certificate the attacker can now incorporate all the other sites, since the trust chain is valid even if the hostname is not. This is the same as if you would accept any kind of identification issued by a state, without even looking if the picture in the I.D. matches the person showing the I.D.
If I'm understanding you correctly, I think you can accomplish what you are trying to do by implementing a HostnameVerifier, and just returning true in the verify method. You can set up the verifier on the ClientBuilder. For example
Client client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.hostnameVerifier(hostnameVerifier)
.build();

Java Security Warning SSL Connection after server change

After a server change, I get nasty SSL warning in browsers (tested FF & Chrome), when loading an applet, used in an JavaEE Application (Serlvet API 3)
The warning says: "Certificate is not valid, and cannot used to identify the website"
The more detailed warning says: "The certificate authority, who provided the certificate, is not trusted." The messages are translated into english, so please excuse slight differences there. After this message, I get the message of Java, which shows that the Applet is ordinary signed (the dialog with the blue sign). So the Applet is working, only the warning message annoys.
Before I moved to another server, everything was fine and worked. No security warnings or anything else. The Applet is signed, by a certificate, which I requested from an CA. (rapidssl)
The old server environment was just a common web space, offered by 3rd party hoster. Now I moved to my own server, which utilizes XEN for hosting VMs. On one of that internal vm's, our webserver is deployed. According to that, I defined firewall rules to route traffic http/https to the vms.
Also the domain was ported, was purchased at old hoster, and the ip of new server is bound to domain.
I use Tomcat 7 as Application Server on an debian based OS.
In old environment, I could use the specified url in CN of my wildcard cert.(e.g. *.domain.com)
In new environment the basic message says: *.domain.com:port is not a trusted site.
I thought actually, that SSL Certs are independent of the used port. I've read that, on some research too. I also searched here in many threads, but the supposed answers didnt work for me.
The certificate and root cert. are imported to Java's own keystore cacerts. In Tomcat 7, I use the JSSE Implementation for SSL, with properly setup keystore files.
I've tried already this, but as im not that experienced with SSL/TLS Technology, the tried solutions maybe even wont solve my problem:
Disabling SNI in Tomcat 7 (dont work)
Adding Host aliases in server.xml (dont work)
Can anyone clarify, what the actual problem is, or has experienced the same issue ?
#edit: The are no error stacktraces in any logs, which I could provide here, also no exceptions gets thrown.
It came clear, thanks to Khanna111 Gaurav Khanna and jwv, that the certificate chain wasnt setup properly. I thought, if there were any problems with the certificate chain, that the browser will notify me about it. It isn't like that.
As we migrated from old hoster to new server, they provided only the certificates, but without the private key.
As im not that much experinced with SSL, I thought that importing the intermediary certs and the acquired cert is enough.. It is not :)
After stumbling on
intermediate-ca-certificate-in-java (link in comment), I've read this, which solved my problem: why doesn't java send the client certificate during SSL handshake? & external website:Import private key and certificate into Java Key Store (JKS)
I had certkey.key,publiccert.crt, intermediate_primary.cer and secondary_primary.cer Files.
The first step was, to convert the .key and .crt file to DER format, as mentioned in last link
via OpenSSL due to keytool's inability to import a key in an existing keystore
After converting to DER Format, I used the Tool ImportKey and created a new keystore with key/cert contained.
The second step was following the instructions of second link (Bruno's Answer), so it was copy&paste the certificate contents, into a single file. After importing the bundle of certificates into keystore, everything was fine.
I hope this can help anyone else, which is also not that familiar with SSL.
p.s. due to my lack of rep, i cannot mention all sites, I've used.. I'll provide them in comments

Do I Really Need to Import a SSL Cert into Java Keystore Manually?

I have a Java web app that has been running fine for several months. It integrates with the Box API (https://upload.box.com/api/2.0) to save files to the cloud service. Out of the blue, we started receiving the dreaded javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated exception while trying to make a REST API call to the Box web service.
There are tons of posts out there that tell you how to manually import the cert into your key store using the keytool utility. I understand that I can do this to fix the problem. But is this really the correct fix?
The fact that my application has been running fine for months leads me to believe something in the certificate at https://upload.box.com changed. Looking at the cert in my web browser, the certificate seems valid and was only renewed a few weeks ago. What is missing from my keystore?
Is it the Root CA certificate that is missing from my keystore? If that is the case, could I just copy the cacerts file from newer version of Java? My app is currently running JDK 1.6.0_33.
I am just trying to understand why this would suddenly stop working and what the "real" fix should be. It doesn't seem like modifying the JDK keystore is the correct thing to do.
I'll just assume you're using Apache HTTP Client 4.x, before 4.2.6, 4.3 Beta2, in which case javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated is most likely to come from a certificate that isn't trusted (otherwise it means the server didn't send a cert, which is a different problem, more details in this answer).
The current cert for server you're trying to access seems to have been issued on 07/04/2014, so this indicates that the certificate, and perhaps its chain has changed recently indeed.
I don't have a JDK 1.6.0_33 at hand, but it's possible that some of these CA certs were not part of the default bundle. In any case, it's worth updating cacerts, even on older JREs (if only to remove CA certs that should no longer be trusted, for example). The JSSE Reference Guide clearly states (admittedly in the middle of a fairly long document, but it's worth searching for "important note"...):
IMPORTANT NOTE: The JDK ships with a limited number of trusted root certificates in the <java-home>/lib/security/cacerts file. As documented in keytool, it is your responsibility to maintain (that is, add/remove) the certificates contained in this file if you use this file as a truststore.
Depending on the certificate configuration of the servers you contact, you may need to add additional root certificate(s). Obtain the needed specific root certificate(s) from the appropriate vendor.
If you can't upgrade your JRE (Java 6 is in general out of support), updating the cacerts file from a more recent version is certainly a sensible compromise.
Besides the various fixes in Java 7, Java 7+ would also allow you to connect to hosts that require SNI (although this doesn't seem to be the case for this particular host).

Validate Extended Validation(EV) of SSL certificate using JSSE

I got list of URLs, and I want to validate their Extended Validation (EV) attribute using JAVA
I can make request and get their certificate, but I am not sure how to validate “Extended Validation” for a given site.
Is there any special value in certificate? Or any attribute?
Extended validation is mostly useful from a user-interface perspective. It's not so useful if your client doesn't have anything in its user interface to display the certificate. These verifications are not integrated by default in the JSSE, possibly because there is little demand for it (lack of Java browsers). (By the way, you should verify the certificate you get upon connection, not check with a first connection and connect with another, just in case).
The specifications are defined by the CA/browser forum.
The OID values and root CA certificate fingerprints are hard-coded into browsers (see security/certverifier/ExtendedValidation.cpp in Firefox, used to be in in security/manager/ssl/src/nsIdentityChecking.cpp). There is also a list on Wikipedia for reference, although in principle you should check the policy OIDs with each CA.
To analyse the extensions, it might be useful to use BouncyCastle if X509Certificate.getExtensionValue() isn't enough.
One problem you will have to watch out for is that the hard-coded SHA-1 fingerprints of the root CA certificates need to match exactly those certificates in the trust store. Some CAs renew their CA certificates once in a while in the bundles that are shipped with most browsers/OS/JREs: make sure you're using the same.

Categories

Resources