##### XML-RPC

- Overview
- Download
- Changes
- Mailing Lists
- Contributing
- XML-RPC 2
- Links

##### Documentation

- Client Classes
- Server Side XML-RPC
- Vendor Extensions
- SSL
- Introspection
- Advanced Techniques
- XML-RPC Types
- FAQ
- Javadocs

##### Project Documentation

- Project Information
- Project Reports

This page describes how to configure a client for using SSL (aka https). Server configuration is out of this documents scope, because it clearly depends on the webserver. We refer, for example, to the Tomcat SSL HowTo or to the FAQ entry on SSL with Jetty.

## Background

Client configuration for SSL is not as simple as one might expect. This is surprising, because using SSL with a browser is as simple as typing in an https URL into the browsers input field.

Thus, the first thing to keep in mind: Never start with Apache XML-RPC as a client. It is much better to create a simple static page and point your browser to the static pages URL. If you get this working, then you may assume that all remaining problems rest with the client.

If you did that, you may have noticed, that the browser brings up a warning, that your web server is "not trusted". This is typically the case, if you did not buy a certificate: For the case of simplicity, developers are typically creating a so-called "self-signed certificate".

And that's exactly your most likely problem: Like pressing the browsers button to "Accept the certificate" (temporarily or permanently), you've got to tell your Java client, that you want to accept the certificate.

## Choose the right URL

Typically, your server may be accessible with multiple URL's. For example, on my machine the following URL's will all reach the same servlet:

https://mcjwi.eur.ad.sag/xmlrpc https://localhost/xmlrpc https://127.0.0.1/xmlrpc

Unfortunately, at most one will work in the most cases. The question is: How do I choose the right one?

The answer is given by the certificate field CN. For example, my self certified key looks like this:

Owner: CN=mcjwi.eur.ad.sag, OU=-, O=-, L=-, ST=-, C=- Issuer: CN=mcjwi.eur.ad.sag, OU=-, O=-, L=-, ST=-, C=-

Note, that you've got to pick a proper CN when generating the certificate! If you are self-certifying the key and the keytool asks you for your own name: Ignore it. In your case the proper reply is the host name.

## The quick and dirty solution

Yes, there is a quick and dirty solution: Just tell your client, that you want to accept any certificate, regardless of issuer and host. This can be done by installing a custom TrustManager and a HostnameVerifier. Add the following code to your clients initialization:

        import java.security.cert.X509Certificate;

        import javax.net.ssl.HostnameVerifier;
        import javax.net.ssl.HttpsURLConnection;
        import javax.net.ssl.SSLContext;
        import javax.net.ssl.SSLSession;
        import javax.net.ssl.TrustManager;
        import javax.net.ssl.X509TrustManager;

        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    // Trust always
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    // Trust always
                }
            }
        };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        // Create empty HostnameVerifier
        HostnameVerifier hv = new HostnameVerifier() {
                    public boolean verify(String arg0, SSLSession arg1) {
                            return true;
                    }
        };

        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(hv);

## The recommended solution

Needless to say, the quick and dirty solution may is insecure, because it can your requests can be intercepted by a man-in-the-middle attack. Fortunately, there is also a clean solution: Import the servers public key into your truststore.

As a first step, you've got to obtain the servers public key. Assuming, that the key is in your keystore, you may export it by running

        keytool -export -alias tomcat -rfc -file tomcat.crt

This example would export the public key named "tomcat" (which is used by Tomcat) into the file "tomcat.crt". The key would be read from your default keystore, which is the file .keystore in your home directory (something like "c:\Documents and Settings\jwi\.keystore" on windows or "/home/jwi/.keystore" on Linux/Unix).

Obviously, this first step must be done on the server. The second step would be to create a truststore on your client by importing the file "tomcat.crt":

        keytool -import -alias servercert -file tomcat.crt -keystore truststore

The option "-keystore truststore" specifies a file name. Of course, this may as well be an absolute path.