I am calling a remote https URL with the following code:
def inputStream = new URL("https://somewebsite.com").openStream()
This works great on my local machine, but when I deploy to the server, I get the following Exception:
java.security.cert.CertPathValidatorException: CA key usage check failed: keyCertSign bit is not set
What is the cause of this error, and what could account for it working on one machine and not another?
UPDATE
I'm running an Ubuntu server in production and developing on a Mac locally. The site I'm trying to access (let's call it peopleware.com) has the following certificate info:
- AddTrust External CA Root
- UTN-USERFirst-Hardware
- peopleware.com
I have tried saving the .cer files from my browser and installing them into the keystore at /etc/ssl/certs/java/castore
I'm assuming that you're talking about this certificate from UTN-USERFirst-Hardware:
In a human-readable version:
Essentially, we have here a CA certificate with both
X509v3 Key Usage
andX509v3 Extended Key Usage
.However, RFC 3280 says the following about the extended key usage extension:
This doesn't start too well for a CA cert, but later on, the same section also says this:
The only extended key usage extension in this cert that is in this RFC is TLS Web Server Authentication:
Of course, this is not consistent with
keyCertSign
, which, according to RFC 3280 (and RFC 5280). (I also doubt any of the IPSec extensions are compatible withkeyCertSign
). This makes this certificate useless to issue certificates (not very useful for a CA certificate).I would contact the website using this certificate to ask them to contact their CA (UTN-USERFirst-Hardware, apparently Comodo) and ask them to fix this. I must say it doesn't look good coming from people who make their money on the back of these RFCs.
Of course, this could take a while and wouldn't solve your immediate problem.
I think I've seen this Subject DN (UTN-USERFirst-Hardware) in other intermediate CA certificates, so the one above might not be the one you're using.
What you might be able to do (provided that you're able to verify the server certificate itself manually despite these problems) is to use an
SSLContext
and aTrustManager
specifically limited to use that very certificate, for this connection. This could prevent the certification path algorithm to try to find the issuer certificate and fall into this problem.EDIT:
Here are more details on this workaround (which should still keep your connection secure).
Use
keytool
to create a new keystore (choose to trust that certificate and choose a sensible password):Then, use this Java code, which shouldn't be too hard to port to Groovy: