private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ... scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery
This document provides an overview of how to configure SSL (also known as TLS) for Jetty.
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:
Certificates:
Keytool:
Other tools:
OpenSSL:
For testing, the keytool
utility bundled with the JDK provides the simplest way to
generate the key and certificate you need.
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, or 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.
To configure Jetty for SSL, complete the tasks in the following sections:
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 Keys and Certificates with JDK's keytool.
If you already have keys and certificates, see Loading Keys and Certificates to load them into a JSSE keystore. 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:
the key size
the certificate expiration date
alternate security providers
The following command generates a key pair and certificate
directly into file keystore
:
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA
The DSA key algorithm certificate produces an error after loading several pages. In a browser, it displays a message "Could not establish an encrypted connection because certificate presented by localhost has an invalid signature." The solution is to use RSA for the key algorithm.
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): $
You now have the minimal requirements to run an SSL connection and could proceed directly to configure an SSL connector. However the browser will not trust the certificate you have generated, and prompts the user to this effect. While what you have at this point is often sufficient for testing, most public sites need a trusted certificate, as shown in the section generating a CSR with keytool.
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 prompts the user to this effect. While what you have at this point is often sufficient for testing, most public sites need a trusted certificate, as shown in the section, Generating a CSR from OpenSSL to obtain a certificate.
If you have keys and certificates from other sources, you can proceed directly to Loading Keys and Certificates.
The keys and certificates generated with JDK's 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).
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
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.
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.
You need both the private key and the certificate in the JSSE
keystore. You should load the certificate into the keystore used to
generate the CSR with keytool
. If your key pair is not already in a keystore
(for example, because it has been generated with OpenSSL), you need to use the PKCS12 format to load
both key and certificate (see PKCKS12 Keys &
Certificates).
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
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
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 is required to make the next step work.
Then load the resulting PKCS12 file into a JSSE keystore with keytool
:
$ keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
The generated SSL certificates held in the key store are configured on Jetty by injection an instance of SslContextFactory object and passing it to the connector's SslConnectionFactory, which is done in the jetty distribution by both in jetty-https.xml and jetty-spdy.xml. Since SPDY is able to handle HTTPS also, typically you will configure jetty to use one of these configuration files or the other, which can be done other on the command line or by editing the start.ini file.
These configuration files create an SslContextFactory instance with the ID "sslContextFactory":
<New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> <Set name="KeyStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set> <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> <Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set> <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> </New>
This example uses the keystore distributed with jetty. To use your own keystore you need to update at least the following settings:
You can either replace the provided keystore with your own, or change the configuration to point to a different file. Note that as a keystore is vital security information, it can be desirable to locate the file in a directory with very restricted access.
The keystore password may be set here in plain text, or as some protection from casual observation, it may be obfuscated using the Password class.
The Truststore is used if validating client certificates and is typically set to the same keystore.
The keyManagerPassword is passed as the password arg to KeyManagerFactory.init(...). If there is no keymanagerpassword, then the keystorepassword is used instead. If there is no trustmanager set, then the keystore is used as the trust store and the keystorepassword is used as the truststore password
For example to avoid the BEAST attack it is necessary to configure a specific set of cipher suites. This can either be done via SslContext.setIncludeCipherSuites(java.lang.String...) or via SslContext.setExcludeCipherSuites(java.lang.String...).
It's crucial that you use the exact names of the cipher suites as used/known by the JDK. You can get them by obtaining an instance of SSLEngine and call getSupportedCipherSuites(). Tools like ssllabs.com might report slightly different names which will be ignored.
Both setIncludeCipherSuites and setExcludeCipherSuites can be feed by the exact cipher suite name used in the jdk or by using regular expressions.
Here's a couple of examples on how to include only RC4 cipher suites. All of them will protect the server from the BEAST attack.
Include a preferred set of cipher suites:
<Set name="IncludeCipherSuites"> <Array type="String"> <Item>TLS_RSA_WITH_RC4_128_MD5</Item> <Item>TLS_RSA_WITH_RC4_128_SHA</Item> <Item>TLS_ECDHE_RSA_WITH_RC4_128_SHA</Item> </Array> </Set>
Include all RC4 cipher suites by using a regex:
<Set name="IncludeCipherSuites"> <Array type="String"> <Item>.*RC4.*</Item> </Array> </Set>
Exclude all non RC4 cipher suites:
<Set name="ExcludeCipherSuites"> <Array type="String"> <Item>SSL_RSA_WITH_DES_CBC_SHA</Item> <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item> <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item> <Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item> <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>TLS_DHE_RSA_WITH_AES_128_CBC_SHA256</Item> <Item>TLS_RSA_WITH_AES_128_CBC_SHA</Item> <Item>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</Item> <Item>TLS_RSA_WITH_AES_128_CBC_SHA256</Item> <Item>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA</Item> <Item>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256</Item> <Item>TLS_RSA_WITH_3DES_EDE_CBC_SHA</Item> <Item>TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA</Item> <Item>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</Item> <Item>RSA_WITH_3DES_EDE_CBC_SHA</Item> </Array> </Set>
It is recommended to use the IncludeCipherSuites with the regex unless you've reasons you need to specify specific cipher suites. This configuration will adapt to any additions/removals of cipher suites to new versions of the JDK.
This SslContextFactory
instance created above is injected into a
SslConnectionFactory
instance to be used when accepting network
connections, which in turn is injected into an instance of
ServerConnector
. For example from jetty-https.xml:
<Call id="sslConnector" name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.ServerConnector"> <Arg name="server"><Ref refid="Server" /></Arg> <Arg name="factories"> <Array type="org.eclipse.jetty.server.ConnectionFactory"> <Item> <New class="org.eclipse.jetty.server.SslConnectionFactory"> <Arg name="next">http/1.1</Arg> <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> </New> </Item> <Item> <New class="org.eclipse.jetty.server.HttpConnectionFactory"> <Arg name="config"><Ref refid="tlsHttpConfig"/></Arg> </New> </Item> </Array> </Arg> <Set name="host"><Property name="jetty.host" /></Set> <Set name="port"><Property name="jetty.tls.port" default="8443" /></Set> <Set name="idleTimeout">30000</Set> </New> </Arg> </Call>
Note also that the SSL connector port is set directly on the ServerConnector instance.
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.
See an error or something missing? Contribute to this documentation at Github!