This is an overview of how to configure SSL for Jetty, which uses Sun's reference implementation for the Java Secure Sockets Extension (JSSE).
Understanding Certificates and Keys
Configuring SSL can be a confusing experience of keys, certificates, protocols and formats, thus it helps to have a reasonable understanding of the basics. The following links provide some good starting points:
- Other tools:
Configuring Jetty for SSL
To configure Jetty for SSL, complete the tasks in the following sections:
OpenSSL Versus Keytool
For testing, keytool probably provides the simplest way to generate the key and certificate you need. However, IBM's keyman is also pretty good, and provides a GUI rather than a command line.
You can also use the OpenSSL tools to generate keys and certificates, or to convert those that you have used with Apache or other servers. Since Apache and other servers commonly use the OpenSSL tool suite to generate and manipulate keys and certificates, you might already have some keys and certificates created by OpenSSL. Also, OpenSSL might be more trusted than keytool or some certificate authorities. You might also prefer the formats OpenSSL produces.
If you want the option of using the same certificate with Jetty or a web server such as Apache not written in Java, you might prefer to generate your private key and certificate with OpenSSL. The Java keytool does not provide options for exporting private keys, and Apache needs the private key. If you create the key and certificate with OpenSSL, your non-Java web server has ready access to it.
Generating Key Pairs and Certificates
The simplest way to generate keys and certificates is to use the keytool application that comes with the JDK, as it generates keys and certificates directly into the keystore. See Generating a Certificate with JDK keytool.
If you already have keys and certificates, see Loading Keys and Certificates to load them into a JSSE key store. This section also applies if you have a renewal certificate to replace one that is expiring.
The examples below generate only basic keys and certificates. You should read the full manuals of the tools you are using if you want to specify:
- Key size.
- Certificate expiry.
- Alternate security providers.
Generating Keys and Certificates with JDK keytool
The following command generates a key pair and certificate directly into a keystore:
keytool -keystore keystore -alias jetty -genkey -keyalg RSA
This command prompts for information about the certificate and for passwords to protect both the keystore and the keys within it. The only mandatory response is to provide the fully qualified host name of the server at the "first and last name" prompt. For example:
keytool -keystore keystore -alias jetty -genkey -keyalg RSA Enter keystore password: password What is your first and last name? [Unknown]: jetty.eclipse.org What is the name of your organizational unit? [Unknown]: Jetty What is the name of your organization? [Unknown]: Mort Bay Consulting Pty. Ltd. What is the name of your City or Locality? [Unknown]: What is the name of your State or Province? [Unknown]: What is the two-letter country code for this unit? [Unknown]: Is CN=jetty.eclipse.org, OU=Jetty, O=Mort Bay Consulting Pty. Ltd., L=Unknown, ST=Unknown, C=Unknown correct? [no]: yes Enter key password for <jetty> (RETURN if same as keystore password): password
You now have the minimal requirements to run an SSL connection and could proceed directly to Configuring Jetty to configure an SSL connector. However the browser will not trust the certificate you have generated, and will prompt the user to this effect. While what you have at this point is often sufficient for testing, most public sites need to request a trusted certificate, as shown in the section, Obtaining a CSR from keytool.
Generating Keys and Certificates with OpenSSL
The following command generates a key pair in the file jetty.key:
openssl genrsa -des3 -out jetty.key
You might also want to use the -rand file argument to provide an arbitrary file that helps seed the random number generator.
The following command generates a certificate for the key into the file jetty.crt:
openssl req -new -x509 -key jetty.key -out jetty.crt
The next command prompts for information about the certificate and for passwords to protect both the keystore and the keys within it. The only mandatory response is to provide the fully qualified host name of the server at the Common Name prompt. For example:
openssl genrsa -des3 -out jetty.key Generating RSA private key, 512 bit long modulus ...........................++++++++++++ ..++++++++++++ e is 65537 (0x10001) Enter pass phrase for jetty.key: Verifying - Enter pass phrase for jetty.key: # openssl req -new -x509 -key jetty.key -out jetty.crt Enter pass phrase for jetty.key: You are about to be asked to enter information to be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there is a default value, If you enter '.', the field is left blank. ----- Country Name (2 letter code) [AU]:. State or Province Name (full name) [Some-State]:. Locality Name (eg, city) :. Organization Name (eg, company) [Internet Widgets Pty Ltd]:Mort Bay Consulting Pty. Ltd. Organizational Unit Name (eg, section) :Jetty Common Name (eg, YOUR name) :jetty.eclipse.org Email Address : #
You now have the minimal requirements to run an SSL connection and could proceed directly to Loading Keys and Certificates to load these keys and certificates into a JSSE keystore. However the browser will not trust the certificate you have generated, and will prompt the user to this effect. While what you have at this point is often sufficient for testing, most public sites need to request a trusted certificate, as shown in the section, Generating a CSR from OpenSSL to obtain a certificate.
Using Keys and Certificates from Other Sources
If you have keys and certificates from other sources, you can proceed directly to Loading Keys and Certificates.
Requesting a Trusted Certificate
The keys and certificates generated with the JDK keytool and OpenSSL are sufficient to run an SSL connector. However the browser will not trust the certificate you have generated, and it will prompt the user to this effect.
To obtain a certificate that most common browsers will trust, you need to request a well-known certificate authority (CA) to sign your key/certificate. Such trusted CAs include: AddTrust, Entrust, GeoTrust, RSA Data Security, Thawte, VISA, ValiCert, Verisign, and beTRUSTed, among others.
Each CA has its own instructions (look for JSSE or OpenSSL sections), but all involve a step that generates a certificate signing request (CSR).
Generating a CSR from keytool
The following command generates the file jetty.csr using keytool for a key/cert already in the keystore:
keytool -certreq -alias jetty -keystore keystore -file jetty.csr
Generating a CSR from OpenSSL
The following command generates the file jetty.csr using OpenSSL for a key in the file jetty.key:
openssl req -new -key jetty.key -out jetty.csr
Notice that this command uses only the existing key from jetty.key file, and not a certificate in jetty.crt as generated with OpenSSL. You need to enter the details for the certificate again.
Loading Keys and Certificates
Once a CA has sent you a certificate, or if you generated your own certificate without keytool, you need to load it into a JSSE keystore.
Loading Certificates with keytool
You can use keytool to load a certificate in PEM form directly into a keystore. The PEM format is a text encoding of certificates; it is produced by OpenSSL, and is returned by some CAs. An example PEM file is:
jetty.crt -----BEGIN CERTIFICATE----- MIICSDCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQQFADBUMSYwJAYDVQQKEx1Nb3J0 IEJheSBDb25zdWx0aW5nIFB0eS4gTHRkLjEOMAwGA1UECxMFSmV0dHkxGjAYBgNV BAMTEWpldHR5Lm1vcnRiYXkub3JnMB4XDTAzMDQwNjEzMTk1MFoXDTAzMDUwNjEz MTk1MFowVDEmMCQGA1UEChMdTW9ydCBCYXkgQ29uc3VsdGluZyBQdHkuIEx0ZC4x DjAMBgNVBAsTBUpldHR5MRowGAYDVQQDExFqZXR0eS5tb3J0YmF5Lm9yZzBcMA0G CSqGSIb3DQEBAQUAA0sAMEgCQQC5V4oZeVdhdhHqa9L2/ZnKySPWUqqy81riNfAJ 7uALW0kEv/LtlG34dOOcVVt/PK8/bU4dlolnJx1SpiMZbKsFAgMBAAGjga4wgasw HQYDVR0OBBYEFFV1gbB1XRvUx1UofmifQJS/MCYwMHwGA1UdIwR1MHOAFFV1gbB1 XRvUx1UofmifQJS/MCYwoVikVjBUMSYwJAYDVQQKEx1Nb3J0IEJheSBDb25zdWx0 aW5nIFB0eS4gTHRkLjEOMAwGA1UECxMFSmV0dHkxGjAYBgNVBAMTEWpldHR5Lm1v cnRiYXkub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADQQA6NkaV OtXzP4ayzBcgK/qSCmF44jdcARmrXhiXUcXzjxsLjSJeYPJojhUdC2LQKy+p4ki8 Rcz6oCRvCGCe5kDB -----END CERTIFICATE-----
The following command loads a PEM encoded certificate in the jetty.crt file into a JSSE keystore:
keytool -keystore keystore -import -alias jetty -file jetty.crt -trustcacerts
Depending on the situation, you might not require the -trustcacerts option. Try the operation without it if you like. If the certificate you receive from the CA is not in a format that keytool understands, you can use the openssl command to convert formats:
openssl x509 -in jetty.der -inform DER -outform PEM -out jetty.crt
Loading Keys and Certificates via PKCS12
If you have a key and certificate in separate files, you need to combine them into a PKCS12 format file to load into a new keystore. The certificate can be one you generated yourself or one returned from a CA in response to your CSR.
The following OpenSSL command combines the keys in jetty.key and the certificate in the jetty.crt file into the jetty.pkcs12 file:
openssl pkcs12 -inkey jetty.key -in jetty.crt -export -out jetty.pkcs12
If you have a chain of certificates, because your CA is an intermediary, build the PKCS12 file as follows:
# cat example.crt intermediate.crt [intermediate2.crt]... rootCA.crt > cert-chain.txt # openssl pkcs12 -export -inkey example.key -in cert-chain.txt -out example.pkcs12
The order of certificates must be from server to rootCA, as per RFC2246 section 7.4.2.
OpenSSL asks for an export password. A non-empty password seems to be required to make the next step work. Then load the resulting PKCS12 file into a JSSE keystore with the following jetty utility class:
java -classpath $JETTY_HOME/lib/jetty-util-6.1-SNAPSHOT.jar:$JETTY_HOME/lib/jetty-6.1-SNAPSHOT.jar org.eclipse.jetty.security.PKCS12Import jetty.pkcs12 keystore
This asks for two passphrases. Give the password from the last step as the input passphrase and you are set. The "output passphrase" must appear in your jetty.xml config file as both the Password and KeyPassword of the SunJsseListener that uses the certificate.
You can also use keytool (starting form jdk1.6) to import a PKCS12 file with the following command:
keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
Beginning with Jetty 7.3.1, the preferred way to configure SSL parameters for the connector is by configuring the SslContextFactory object and passing it to the connector's constructor.
Jetty has two SSL connectors–the SslSocketConnector and the SslSelectChannelConnector. The SslSocketConnector is built on top of the Jetty SocketConnector which is Jetty's implementation of a blocking connector. It uses Java's SslSocket to add the security layer. The SslSelectChannelConnector is an extension of Jetty's SelectChannelConnector which uses non-blocking IO. For its security layer, it uses java nio SslEngine. You can configure these two connectors similarly; the difference is in the implementation.
The following is an example of an SslSelectChannelConnector configuration. You can configure an SslSocketConnector the same way–just change the value of the class to org.eclipse.jetty.server.ssl.SslSocketConnector.
<Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector"> <Arg> <New class="org.eclipse.jetty.http.ssl.SslContextFactory"> <Set name="keyStore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> <Set name="keyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> <Set name="keyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> <Set name="trustStore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> <Set name="trustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> </New> </Arg> <Set name="port">8443</Set> <Set name="maxIdleTime">30000</Set> </New> </Arg> </Call>
Other properties that you can set for the SslContextFactory include:
- certAlias–Alias of a certificate to use.
- keyStoreType–Default value: "JKS."
- keyStoreProvider–Default is the SunJSSE provider.
- trustStoreType–Default value: "JKS".
- trustStoreProvider–Default is the SunJSSE provider.
- sslKeyManagerFactoryAlgorithm–Set to the value of the "ssl.KeyManagerFactory.algorithm" system property. If there is no such property, the default is "SunX509."
- sslTrustManagerFactoryAlgorithm–set to the value of the "ssl.TrustManagerFactory.algorithm" system property. If there is no such property, the default is "SunX509."
- secureRandomAlgorithm–Default value is null.
- protocol–Default value is "TLS."
- provider–Default is the first provider that supports that protocol.
- includeCipherSuites–See How to configure SSL Cipher Suites.
- excludeCipherSuites–See How to configure SSL Cipher Suites.
- needClientAuth–Default is false
- wantClientAuth–Defaults is false.
- validateCerts–Default is false.
- allowRenegotiate–Default is false.
- crlPath–Path to certificate revocation list file for SSL certificate validation.
- maxCertPathLengh–Maximum allowed number of intermediate certificates, default is -1 (unlimited).
If there is no value for the truststore, the system uses the keystore value. You can obfuscate passwords by using the Jetty password utility.
Choosing a Directory for the keystore
The keystore file in the example above is given relative to the jetty home directory. For production, choose a private directory with restricted access to keep your keystore in. Even though it has a password on it, the password may be configured into the runtime environment so is vulnerable to theft. You can now start Jetty the normal way (make sure that jcert.jar, jnet.jar and jsse.jar are on your classpath) and SSL can be used with a URL like:
Setting the Port for https
Remember that the default port for https is 443 not 80, so change 8443 to 443 if you want to be able to use URLs without explicit port numbers. For a production site it normally makes sense to have an HttpListener on port 80 and a SunJsseListener on port 443. Because these are privileged ports, you might want to use a redirection mechanism to map port 80 to, for example, 8080 and 443 to, for example, 8443. For details on this, see Accessing Port 80 as a non-Root User.
Redirecting http requests to https
To redirect http to https, the webapp should indicate it needs CONFIDENTIAL or INTEGRAL connections from users. This is done in web.xml:
<web-app> ... <security-constraint> <web-resource-collection> <web-resource-name>Everything in the webapp</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> </web-app>
Then you need to tell the plain http connector if the users try to access that webapp using plain http, they should be redirected to the port of your ssl connector (the "confidential port"):
<Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.nio.SelectChannelConnector"> ... <Set name="confidentialPort">443</Set> </New> </Arg> </Call>
That's it. If the webapp doesn't indicate it needs CONFIDENTIAL or INTEGRAL connections (as it may be considered a deployment issue), you can set this requirement in the context (so you must deploy the webapp as a WebAppContext instead of just a war file):
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="securityHandler"> <New class="org.eclipse.jetty.security.ConstraintSecurityHandler"> <Call name="addConstraintMapping"> <Arg> <New class="org.eclipse.jetty.security.ConstraintMapping"> <Set name="pathSpec">/*</Set> <Set name="constraint"> <New class="org.eclipse.jetty.util.security.Constraint"> <!-- 2 means CONFIDENTIAL. 1 means INTEGRITY --> <Set name="dataConstraint">2</Set> </New> </Set> </New> </Arg> </Call> </New> </Set> </Configure>
Configuring SSL for Earlier Versions of Jetty
For instructions on configuring SSL for versions earlier than Jetty 7.3.1, refer to Using Deprecated Methods to Configure SSL for Jetty.
If the configuration does not include passwords, you can provide them as as java properties (jetty.ssl.password and jetty.ssl.keypassword), else the system prompts for them. Remember that putting your password on the command line is a security risk. You can also set them as properties within the config file, but this risks accidental discovery by developers.
If jetty is given a password that begins with "OBF:" it is treated as an obfuscated password. You can obfuscated passwords by running org.eclipse.jetty.http.util.Password as a main class. This can protect passwords from casual observation.
If you are updating your configuration to use a newer certificate, as when the old one is expiring, just load the newer certificate as described in the section, Loading Keys and Certificates. If you imported the key and certificate originally using the PKCS12 method, use an alias of "1" rather than "jetty", because that is the alias the PKCS12 process enters into the keystore.