Hi,

Ben Johnson wrote:
Hi
I am new to Restlet and web programming, HTTP and SSL certificates in general, but hopefully my recent experiences will help. I spent the last several days trying to find a Restlet example using HTTPS (there isn't one), and eventually pieced together the following (using Windows XP SP2 with Java 6, Eclipse, Restlet 1.1.1): 1) Create your keys and certificate. I tried both 'keytool' and IBM's KeyMan to do this (KeyMan is easier, but more work to obtain, as you need to register, etc...). Using keytool from a command prompt you need to enter two commands - the first one creates the keystore file with the keys, the second certifies it (self-certification, ok for testing). The most important thing is that the name of the machine you will be using the certificate on matches what you specify (in the example below, my machine is called 'serverX'): keytool -genkey -dname "CN=serverX, OU=IT, O=JPC, C=GB" -alias serverX -keypass password -keystore serverX.cer -storepass password -keyalg "RSA" -storetype "PKCS12" -provider sun.security.provider.Sun keytool -selfcert -alias serverX -keystore serverX.cer -storepass password -storetype "PKCS12" The keystore file has now been created and self-certified: in this example it is called 'serverX.cer' and was saved in the current directory. There are two passwords: one for the keys and one to access the keystore. I set them both to 'password' for testing. The name of the keystore file ('serverX.cer') is not important, I just used that for consistency.

Usually, the extension for JKS keystores is "jks" and the extension for PKCS#12 keystores is "p12". "cer" tends to be used for X.509 certificates in DER format (application/x-x509-ca-cert), which are files containing just the certificate: this is the format produced by "keytool -export". It looks from the example below that you've used "jks" for that, whereas it's not actually a JKS file but a cer file.


2) To prevent warnings in a browser, add the keystore to the 'Trusted Root Certification Authorities' on your computer. In Windows XP, I just used Internet Options (via IE7 or Control Panel - Internet Options). On the 'Content' tab, click 'Certificates', then go to 'Trusted Root Certification Authorities' tab, click 'Import...' and follow the steps to import your keystore file (in my example, 'serverX.cer'). It will give warnings about not being verified, which is ok for testing (but it must be properly signed for production).

Since your .cer is in fact a .p12, this might import the private key as well (that's what you would do if you wanted to use client-certificate authentication). In fact, the actual .cer exported by keytool should be sufficient. Just to clarify the extensions:

keytool -export -alias serverX -file serverX.cer -storetype "PKCS12" -keystore serverX.p12 -keypass password

(Shouldn't this be "-storepass" rather than "-keypass" by the way?)


3) In order for Java security to recognise the certificate, it needs to be added to <JRE>\lib\security\cacerts, which is the Java certificates file. This is important when you use a Restlet client to connect to the server via HTTPS (but it did not seem to be needed by my browser - it needed the IE options update described in point 2). On my system, 'cacerts' is "C:\Program Files\Java\jre6\lib\security\cacerts". I had some trouble adding my 'serverX' certificate to it, but the following keytool commands work if you know the password for cacerts ('changeit' is the default I believe): keytool -export -alias serverX -file serverX.jks -storetype "PKCS12" -keystore serverX.cer -keypass password keytool -import -alias serverX -file serverX.jks -noprompt -trustcacerts -keystore "C:\Program Files\Java\jre6\lib\security\cacerts" The first command exports the certificate from PKCS12 format into X.509 (JKS) format, which is what cacerts needs. In my case, I had to use KeyMan to set the password for the 'cacerts' file (I set it back to the default of 'changeit'), so when I ran 'keytool -import ...' I could enter the correct password. There may be a better/easier way to do this.

If for some reason, you can write to that file (which is likely to be shared by all users on that system), you can specify your own truststore using -Djavax.net.ssl.trustStore=mytruststore.jks -Djavax.net.ssl.trustStore=JKS -Djavax.net.ssl.trustStorePassword=ABCDEFGH as JVM parameters.

If you're requiring client-authentication (in which case it makes sense to set up a trust store on the server), you can used the truststorePath, truststorePassword and truststoreType parameters of the Restlet Server when you're using the sslContextFactory (as you've done below). There's currently no SSLContextFactory support in the client connectors of Restlet, so you'll have either to modify the central cacerts as you did, or use the SSL system properties.


As a side note, the "C:\Program Files\Java\jre6\lib\security\cacerts" is the set of defaults CA certificates your JVM will trust. However, I remember seeing somewhere on the Sun documentation that it's up to the user to make sure they're up to date. (It sounds normal, but I'm not sure all users do so.)


4) In your Java Restlet server program, in addition to the standard Restlet jar files, you also need jar files for HTTPS. The only HTTPS connector I could get to work correctly was 'Simple', which uses these jar files: lib/com.noelios.restlet.ext.simple_3.1.jar lib/org.simpleframework_3.1/org.simpleframework.jar lib/com.noelios.restlet.ext.ssl.jar
lib/org.jsslutils_0.5/org.jsslutils.jar
(Grizzly compiled and ran, but gave inconsistent results - appeared to be missing requests; Jetty threw an error saying it couldn't register 'AjpServerHelper'). 5) Your Restlet server code should then look something like this: package com.jpc.samples; import org.restlet.Component;
import org.restlet.Server;
import org.restlet.data.Parameter;
import org.restlet.data.Protocol;
import org.restlet.util.Series;
public class SampleServer { public static void main(String[] args) throws Exception {
    // Create a new Component.
Component component = new Component(); // Add a new HTTPS server listening on port 8183
    Server server = component.getServers().add(Protocol.HTTPS, 8183);
Series<Parameter> parameters = server.getContext().getParameters(); parameters.add("sslContextFactory", "com.noelios.restlet.ext.ssl.PkixSslContextFactory");
    parameters.add("keystorePath", "<path>serverX.cer");
    parameters.add("keystorePassword", "password");
    parameters.add("keyPassword", "password");
    parameters.add("keystoreType", "PKCS12");
// Attach the sample application.
    component.getDefaultHost().attach("", new SampleApplication());
// Start the component.
    component.start();
  }
}
The HTTP examples all show 'component.getContext().getParameters().add(...) but this doesn't seem to work for any HTTPS connectors. Using the server.getContext().getParameters().add(...) does work but this doesn't seem to be clearly documented anywhere.

The reason it doesn't work when setting the component context is due to a change between Restlet 1.0 and 1.1: the contexts are now separate and SSL parameters are specific to the server connector. It's documented in the wiki page "Migration guide from Restlet 1.0 to 1.1", but indeed, it doesn't clearly say how it impacts the SSL configuration. You can also find some documentation about SSL on the wiki: http://wiki.restlet.org/docs_1.1/13-restlet/28-restlet/153-restlet.html Admittedly, this could be improved, especially with some background on what the keystores and truststores are, etc.



Best wishes,

Bruno.


Reply via email to