[SalesForce] SSL Exception when calling out: “System.CalloutException: IO Exception: java.security.cert.CertificateException: No subject alternative names present”

When I call out to an external webservice, I'm getting the following exception "System.CalloutException: IO Exception: java.security.cert.CertificateException: No subject alternative names present".

I haven't had this problem previously when doing 1-way or 2-way SSL – we've used Server Certificates with no SAN (Subject Alternative Name) before, and they worked perfectly fine.

I've checked the Remote Site Settings and there is definitely an entry pointing to the IP address in the CN (Common Name) field on the server certificate.

The endpoint in my code is definitely pointing to the same CN as is on the server certificate, and I'm using https.

Help?

Note that this is (probably going to be, in 2 days!) self-answered, if you have anything further to add, or if the way your problem arose differs to the scenario in the question, let me know in comments, or edit the question or answer as appropriate. If you think the answer I've given to this question is off base, feel free to add a completely new answer instead of commenting on mine

Best Answer

This is sort of a Java problem, rather than an entirely Salesforce-specific problem, so depending on how you search for the answer, it could take you a while to get to why it failed, and what the actual solution is.

Basically: The Java used by Salesforce/Apex for SSL handshaking requires that the server certificate has a SAN (Subject Alternative Name) that matches the CN (Common Name) when the CN is an IP Address. This isn't an issue when the CN is a Hostname.

As such, as you can't use any of the (not particularly nice anyway) java workarounds for this issue; the solution to this involves generating a new server certificate with extra info on it. If you control the web service you're calling out to, that should be reasonably easy - otherwise you will need to get in touch with whoever administers the server and its certs and ask them to do this, as this is a definite blocker with no known workarounds in Salesforce (unless anyone else wants to chime in with one!).

Either way, someone will need to pay for a new Public CA signed server certificate to replace the old one. Depending on your Public CA, you will need to make sure you are buying a cert type that allows SANs, and be aware there may be extra charges per SAN added, depending on your provider.

To include the required SAN using Java 7's keytool, use the flag -ext san=ip:0.0.0.0 - filling in the appropriate IP address here, that matches the CN IP address, instead of 0.0.0.0.

To include the required SAN using openssl, include the following in your openssl.conf file used for generation

[req]
req_extensions = v3_req

[v3_req]
subjectAltName = @alt_names

[alt_names]
IP.1 = 0.0.0.0

Again, filling in the appropriate IP address that matches your CN, instead of 0.0.0.0

The Java flavoured Q&A can be found at https://stackoverflow.com/questions/8443081/