W3C logo
Jigsaw

Jigsaw
SSL configuration


Jigsaw Home / Documentation Overview

In the first part of the tutorial, SSL is being configured for server authentication.
In the second part, the SSL configuration is extended for also providing client authentication.

SSL configuration is a two-step process. First the SSL certificates need to be created, and then the jigsaw server needs to be configured. One item not covered in this document is the importing of already existing certificates.

Make sure that jdk 1.4 is being used.

We are going to be using the SSL implementation from Sun. Mainly the keytool (http://java.sun.com/j2se/1.4/docs/tooldocs/solaris/keytool.html) is used to configure the SSL certificates. If keytool is not in your default PATH, you can find it in the "bin" directory of your JDK installation.

  1. Create a directory under jigsaw for the keystore keeping the server certificate, which is presented to accessing clients
  2. Run the jdk's keytool to first generate the self signed server certificate

    Example:
    keytool -genkey -alias troi.example.com -keypass example -keystore /opt/jigsaw/dev/Jigsaw/keystore/troi.keystore -keyalg RSA
  3. Run the keytool again to make a certificate request. This is what is sent to verisign or our own certificate authority. You can skip this if you want to sign it yourself.

    Example - specifying the output is put into a file:
    keytool -certreq -alias troi.example.com -keypass example -keystore /opt/jigsaw/dev/Jigsaw/keystore/troi.keystore -file troi.csr
    It will output something like:
          -----BEGIN NEW CERTIFICATE REQUEST-----
          MIICgTCCAj4CAQAwezELMAkGA1UEBhMCVVMxETAPBgAAAAgTCElsbGlub2lzMRYwFAYDVQQHEw1E
          b3duZXJzIEdyb3ZlMRAwDgYDVQQKEwdQZXJzZWNvMRkwFwYDVQQLExBCdXNpbmVzcyBTeXN0ZW1z
          MRQwEgYDVQQDEwtCcmlhbiBMYWlyZDCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLf
          Spwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQ
          paSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd
          0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX
          TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j
          fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDc5Ki4
          7dX93se92yzYjxJIi99R9EZYHu4sNUH9obMQYO7o5u/3AOkxzqHLx60wWbf9JoCAlMe8q2i28NNC
          hjsN6LN7V0fgA05k/CzM9pMxbgeA0dqwQrtroWkJnFyzzFLrxjv7Rrh5RDGV/+ZeR72ZpHwy1GOj
          yDB2Dz+NE98sgKAAMAsGByqGSM44BAMFAAMwADAtAhRumfMg6P1KJmstMYga74KxaPLBfgIVAIwB
          bVanNqQb898bqHBkRybHIFqW
          -----END NEW CERTIFICATE REQUEST-----
    

    Now we will import the response from the certificate authority.

    keytool -import -alias sis.example.com -keystore sis.keystore -file sis.cer -keyalg RSA -trustcacerts

    and skip the next point (related to self-signature)

  4. If you want to self-sign the certificate, you may proceed like this:

    Example:
    keytool -selfcert -alias troi.example.com -keystore /opt/jigsaw/dev/Jigsaw/keystore/troi.keystore -keyalg RSA
  5. Create a new configuration file called https-XXXXX.props where the XXXXX is the outside service (ex: enter.example.com). You can copy the default http- server.props to get started
  6. Edit the https-XXXXX.props file and add the following entries:
          # Points to the key store (cf. 4. above, don't forget to put the full path to the keystore)
          org.w3c.jigsaw.ssl.keystore.path=
          # Supplies the password for accessing the key store ...
          org.w3c.jigsaw.ssl.keystore.password=
          # Finally, the socket client factory has to be set to the SSL factory ...
          org.w3c.jigsaw.http.ClientFactory=org.w3c.jigsaw.https.socket.SSLSocketClientFactory
    

    Of course you may change the default port to use the default one for SSL: 443 (or any other you like and which is not yet used)

    You should also change the propfile value to match the name of your configuration file.

  7. Edit the server.props to use the new configuration file and add the following when creating the new server configuration

    Example - note the piece in bold. That lets jigsaw know, which listener daemon to start:
    org.w3c.jigsaw.daemon.handlers=https-server|...
    https-server.org.w3c.jigsaw.daemon.class=org.w3c.jigsaw.https.httpsd
    

This should cover the setup requirements. You should be able to start jigsaw and see something like the following when the start up occurs:

Jigsaw[2.2.3]: serving at https://troi:8002/

You can also use the secure protocol for webdav, in which case the daemon class must be set to

org.w3c.jigsaw.webdavs.webdavsd

Server authentication enables a client to verify in a secure way, which server she or he is talking to.


Jigsaw also provides for client authentication, which addresses the other way around: It enables a server (and a web application) to verify in a secure way, which client accesses the server. Although, client authentication is rarely used in the web, it is a powerful infrastructure for building up secure web applications with distributed user management.

For verifying clients, they must present a certificate, which can be checked by the server using public key infrastructure.
In order to do so, the server needs an additional store for also keeping track of trusted CA certificates used to sign client certificates.

Extending the SSL configuration is a two-step process again. First the trust store has to be populated with CA certificates (at least one), and then the jigsaw server needs to be configured.

You can obtain a client certificate from an authority like verisign and store it in your browser for being presented to the server during the SSL handshake. In this case, you also need to import the authority's certificate used to sign yours into the server's trust store. The latter task can be performed using keytool again.

If you prefer acting as your own CA, keytool and the SUN JCE implementation are not sufficient, because they currently do not provide for signing certificates other than your own. However, you can download a free JCE extension from bouncy castle, which also provides for certificate signing features. You can modify the following sample code for playing CA:

Make sure that the bouncy castle bcprov-jdk14-121.jar file is in your JRE/lib/ext directory.

/**
 * Copyright (c) 2004 Thomas Kopp
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
import java.io.*;
import java.util.*;

import java.security.Security;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.*;

import org.bouncycastle.jce.*;
import org.bouncycastle.jce.provider.*;
import org.bouncycastle.asn1.x509.*;

/**
 * Sample signing utility developped for simplified interoperability with keytool.
 *
 * It assumes that the CA has a self-signed certificate with alias "ca" in the "ca.db" JKS type keystore.
 * In addition, it assumes that a self-signed client certificate with alias "foo" resides in
 * the "bar.db" JKS type keystore. The CA-signed version gets stored with alias "foo" again in 
 * the "bar.p12" PKCS12 type keystore, so that it can easily be imported by web browsers.
 *
 * The ca uses the "manager" password for accessing its own store and the "example"
 * password for accessing the client stores and certificates.
 */ 
public class signtool {

    static {
              // add the bouncy castle provider
              Security.addProvider(new BouncyCastleProvider());
    }
    
    public static void main(String[] args) {
        try {
              // The issuer certificate access
              KeyStore ksca = KeyStore.getInstance("JKS");
              ksca.load(new FileInputStream("ca.db"), "manager".toCharArray());
              X509Certificate cacert = (X509Certificate)ksca.getCertificate("ca");
              PrivateKey caprivate = (PrivateKey)ksca.getKey("ca", "manager".toCharArray());

              // The subject certificate access
              KeyStore ksbar = KeyStore.getInstance("JKS");
              ksbar.load(new FileInputStream("bar.db"), "example".toCharArray());
              X509Certificate foocert = (X509Certificate)ksbar.getCertificate("foo");
              PrivateKey fooprivate = (PrivateKey)ksbar.getKey("foo", "example".toCharArray());

              // The certificate chain building process
              X509V3CertificateGenerator engine = new X509V3CertificateGenerator();
              engine.setSerialNumber(foocert.getSerialNumber());
              engine.setSignatureAlgorithm(foocert.getSigAlgName());
              engine.setNotBefore(foocert.getNotBefore());
              engine.setNotAfter(foocert.getNotAfter());
              engine.setPublicKey(foocert.getPublicKey());
              engine.setSubjectDN(new X509Name(true, foocert.getSubjectX500Principal().getName()));
              engine.setIssuerDN(new X509Name(true, cacert.getIssuerX500Principal().getName()));
              
              // ... and a little signature ...
              X509Certificate foosigned = engine.generateX509Certificate(caprivate);
              
              X509Certificate[] signedchain = new X509Certificate[] { foosigned, cacert };
              
              // The signed certificate update
              KeyStore ksbarca = KeyStore.getInstance("PKCS12", "BC");
              ksbarca.load(null, null); // for initializing the keystore
              ksbarca.setKeyEntry("foo", fooprivate, "example".toCharArray(), signedchain);
              ksbarca.store(new FileOutputStream("bar.p12"), "example".toCharArray());
              
              System.out.println(Arrays.asList(signedchain));
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Now, being able to set up a server-side trust store keeping a CA certificate and to import a CA-signed certificate into your browser's certificate store, we can complete the client authentication configuration.

  1. Create a key store (named "trust store") with keytool containing your self-signed or a true, imported CA certificate. (cf. previous section for details)
  2. Create a key store with keytool containing your own self-signed client certificate.
  3. Either sign your own client certificate with your own CA certificate as explained above or let it sign by a true CA.
  4. Import the signed client certificate into your browser's certificate store.

    Note: Browsers normally require the PKCS#12 key store type for import.

  5. Edit the https-XXXXX.props file and add the following entries:
          # Points to the trust store (cf. 1. above, don't forget to put the full path to the truststore)
          org.w3c.jigsaw.ssl.truststore.path=
          # Supplies the password for accessing the trust store ...
          org.w3c.jigsaw.ssl.truststore.password=
          # Optionally, you can decide, whether to force clients (right side set to: true) to authenticate or 
          # also admit a client without successful authentication (right side set to: false), which is the default
          org.w3c.jigsaw.ssl.must.authenticate=
    

This should cover the setup requirements. When starting and accessing a server url, you should (after server certificate presentation) be asked to type your browser's certificate store password, because the server wants to check your client certificate. If this is successful or the org.w3c.jigsaw.ssl.must.authenticate option is set to false you are allowed to continue.

Note, client certificates and other SSL characteristics are also transparent to a servlet via the getAuthType, getRemoteUser, getUserPrincipal methods and the following request attributes of the servlet api:

 javax.servlet.request.cipher_suite
 javax.servlet.request.key_size
 javax.servlet.request.X509Certificate