0

I am trying to call an endpoint with https that is something like : POST https://193.321.1.321/customers

but I get the error: java.security.cert.CertificateException: No subject alternative names present

Indeed, there is no SAN in my certificate. I was under the impression that, if there is no SAN, it will just check the CN, but looking at the implementation in java we can see that it only checks the CN if the address I am trying to call is NOT an IP . If it is an IP and the certificate does not have SAN, then an exception is thrown ! :

sun.security.util.HostnameChecker

    public void match(String var1, X509Certificate var2) throws CertificateException {
        if (isIpAddress(var1)) {
            matchIP(var1, var2);
        } else {
            this.matchDNS(var1, var2);
        }

    }

    private static boolean isIpAddress(String var0) {
        return IPAddressUtil.isIPv4LiteralAddress(var0) || IPAddressUtil.isIPv6LiteralAddress(var0);
    }

    private static void matchIP(String var0, X509Certificate var1) throws CertificateException {
        Collection var2 = var1.getSubjectAlternativeNames();
        if (var2 == null) {
            throw new CertificateException("No subject alternative names present");
        } else {
            Iterator var3 = var2.iterator();

            while(var3.hasNext()) {
                List var4 = (List)var3.next();
                if ((Integer)var4.get(0) == 7) {
                    String var5 = (String)var4.get(1);
                    if (var0.equalsIgnoreCase(var5)) {
                        return;
                    }

                    try {
                        if (InetAddress.getByName(var0).equals(InetAddress.getByName(var5))) {
                            return;
                        }
                    } catch (UnknownHostException var7) {
                        ;
                    } catch (SecurityException var8) {
                        ;
                    }
                }
            }

            throw new CertificateException("No subject alternative names matching IP address " + var0 + " found");
        }
    }

    private void matchDNS(String var1, X509Certificate var2) throws CertificateException {
        try {
            new SNIHostName(var1);
        } catch (IllegalArgumentException var9) {
            throw new CertificateException("Illegal given domain name: " + var1, var9);
        }

        Collection var3 = var2.getSubjectAlternativeNames();
        if (var3 != null) {
            boolean var4 = false;
            Iterator var5 = var3.iterator();

            while(var5.hasNext()) {
                List var6 = (List)var5.next();
                if ((Integer)var6.get(0) == 2) {
                    var4 = true;
                    String var7 = (String)var6.get(1);
                    if (this.isMatched(var1, var7)) {
                        return;
                    }
                }
            }

            if (var4) {
                throw new CertificateException("No subject alternative DNS name matching " + var1 + " found.");
            }
        }

        X500Name var10 = getSubjectX500Name(var2);
        DerValue var11 = var10.findMostSpecificAttribute(X500Name.commonName_oid);
        if (var11 != null) {
            try {
                if (this.isMatched(var1, var11.getAsString())) {
                    return;
                }
            } catch (IOException var8) {
                ;
            }
        }

        String var12 = "No name matching " + var1 + " found";
        throw new CertificateException(var12);
    }

The (best) solution I found is to generate a new certificate that includes SAN. Unfortunately, the certificate is not mine and I do not think the owners will be ok with generating a new one.

The only other solution I found is to skip host validation all together like in the answer accepted here : answer But, obviously, that is not something acceptable in a PROD environment.

Can I do something LIKE the second solution, that is edit the default behavior when checking the host, but not skip it entirely, rather (maybe) overwrite isIpAddress method to always return false so that the host is checked using the matchDNS method instead of the matchIp one ?

Or is there any other way I can force java to check the IP against the CN, rather than look for SAN ?

ROBLCSnail
  • 13
  • 5
  • Can you see if any of the answers here helps: https://stackoverflow.com/questions/19540289/how-to-fix-the-java-security-cert-certificateexception-no-subject-alternative ? – pringi Jul 20 '22 at 11:05
  • @pringi the answers there either suggest skipping validation all together or suggest making a new cert that contains SAN . there is also an answer regarding ldap, but that is not the case here. That question was the one I should have linked when I referenced the other "solutions" i found, my mistake. – ROBLCSnail Jul 20 '22 at 11:11
  • 22 years. It's been 22 years since the use of the CN for hostname checking was deprecated. – President James K. Polk Jul 24 '22 at 23:10
  • @PresidentJamesK.Polk It is sad that there are people these days that are still emitting 22 year absolute certificates :( – ROBLCSnail Jul 26 '22 at 06:28

0 Answers0