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.
keytool -genkey -alias troi.example.com -keypass example -keystore
/opt/jigsaw/dev/Jigsaw/keystore/troi.keystore -keyalg RSAkeytool -certreq -alias troi.example.com -keypass example -keystore
/opt/jigsaw/dev/Jigsaw/keystore/troi.keystore -file troi.csr
-----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 -trustcacertsand skip the next point (related to self-signature)
keytool -selfcert -alias troi.example.com -keystore
/opt/jigsaw/dev/Jigsaw/keystore/troi.keystore -keyalg RSA
# 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.
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.webdavsdServer 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.
# 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