ChatGPT解决这个技术问题 Extra ChatGPT

SSLHandshakeException: No subject alternative names present

I am invoking HTTPS SOAP web service through java code. I have already imported self-signed certificate in jre cacerts keystore. Now I am getting :

com.sun.xml.internal.ws.com.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present

The hostname of the service URL is not matching that of the CN provided in cert. I read about a workaround of defining a custom Hostname verifier here. But i cant able to make where I should implement the workaround in my code.

public SOAPMessage invokeWS(WSBean bean) throws Exception {

    SOAPMessage response=null;
    try{

    /** Create a service and add at least one port to it. **/
    String targetNameSpace = bean.getTargetNameSpace();
    String endpointUrl = bean.getEndpointUrl();
    QName serviceName = new QName(targetNameSpace, bean.getServiceName());
    QName portName = new QName(targetNameSpace, bean.getPortName());
    String SOAPAction = bean.getSOAPAction();
    HashMap<String, String> map = bean.getParameters();


    Service service = Service.create(serviceName);
    service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);

    /** Create a Dispatch instance from a service. **/
    Dispatch dispatch = service.createDispatch(portName, SOAPMessage.class,
            Service.Mode.MESSAGE);

    // The soapActionUri is set here. otherwise we get a error on .net based
    // services.
    dispatch.getRequestContext().put(Dispatch.SOAPACTION_USE_PROPERTY,
            new Boolean(true));
    dispatch.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY,
            SOAPAction);

    /** Create SOAPMessage request. **/
    // compose a request message
    MessageFactory messageFactory = MessageFactory.newInstance();
    SOAPMessage message = messageFactory.createMessage();

    // Create objects for the message parts
    SOAPPart soapPart = message.getSOAPPart();
    SOAPEnvelope envelope = soapPart.getEnvelope();
    SOAPBody body = envelope.getBody();

    SOAPElement bodyElement = body.addChildElement(bean.getInputMethod(),
            bean.getPrefix(), bean.getTargetNameSpace());

             ...more code to form soap body goes here

    // Print request
    message.writeTo(System.out);

    // Save the message
    message.saveChanges();

    response = (SOAPMessage)dispatch.invoke(message);
    }
    catch (Exception e) {
        log.error("Error in invokeSiebelWS :"+e);
    }
    return response;
}

Please ignore WSBean parameter as the namespaces and other wsdl attributes are coming from this bean. And if this exception can solved with some different workarounds, pls do suggest.

Is your service URI using an IP address or a host name?

S
Steven Levine

Thanks,Bruno for giving me heads up on Common Name and Subject Alternative Name. As we figured out certificate was generated with CN with DNS name of network and asked for regeneration of new certificate with Subject Alternative Name entry i.e. san=ip:10.0.0.1. which is the actual solution.

But, we managed to find out a workaround with which we can able to run on development phase. Just add a static block in the class from which we are making ssl connection.

static {
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
        {
            public boolean verify(String hostname, SSLSession session)
            {
                // ip address of the service URL(like.23.28.244.244)
                if (hostname.equals("23.28.244.244"))
                    return true;
                return false;
            }
        });
}

If you happen to be using Java 8, there is a much slicker way of achieving the same result:

static {
    HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals("127.0.0.1"));
}

You could have generated a certificate with CN=localhost instead.
OK. There's still a slight risk that a MITM could produce a cert with that IP address (since you're not verifying it matches the cert you're after). This being said, it's unlikely that a proper CA will issue a cert to an IP address anyway.
Actually, this was a case of internal organisation development, where the server guys dnt want to go for a CA approved cert nor they want to take pain(sarcasm) of regenerating the cert. So, this little tweak we have to do in our client side code.
We are using Play Framework . Our request is made in a Controller. We simply put your code in the Controller (changing the IP) and it worked!
It's like magic, using it to allow a localhost with forwarded ports to connect through a remote machine to a server from a Groovy class. Thanks.
C
Community

Unlike some browsers, Java follows the HTTPS specification strictly when it comes to the server identity verification (RFC 2818, Section 3.1) and IP addresses.

When using a host name, it's possible to fall back to the Common Name in the Subject DN of the server certificate, instead of using the Subject Alternative Name.

When using an IP address, there must be a Subject Alternative Name entry (of type IP address, not DNS name) in the certificate.

You'll find more details about the specification and how to generate such a certificate in this answer.


thnks, i do understand this is since the self signed certificate generated at server uses a DNS name which doesnt matches the ip i am hitting. But there is nothing i can do about it, since its not in my control. I need a workaround which can be bad in wrong run but atleast solve my problem for time being.
If the host name in the certificate doesn't resolve to the address, the server is mis-configured. Nevertheless, you should be able to alter your local DNS resolution to point that name to this IP address in your /etc/hosts file (if under Linux, or its Windows equivalent).