Prerequisites
This assumes:
- I have already created a private key
myapp.org.key
:
1
|
openssl genrsa -out myapp.org.key 2048
|
- I have used my key to create a CSR:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
openssl req -new -newkey rsa:2048 -nodes \
-key myapp.org.key \
-out myapp.csr
Country Name: [whatever]
State: [whatever]
Locality: [whatever]
Organization Name: [whatever]
Organizational Unit: [whatever]
Common Name: www.myapp.org
Email Address: .
A challenge password: <LEAVE BLANK>
An optional company: <LEAVE BLANK>
|
- I have used the CSR to request a cert, performed the DNS validation, and received the certificate from the certificate provider (not Let’s Encrypt in this case).
The certificate file is www_myapp_org.crt
and in my case is in the PEM format.
Tomcat Configuration
For Tomcat, I do not use the additional certificates which create the full certificate chain - but, if needed, these can be concatenated to the end of the certificate file (after the certificate for my site, which must come first in the file).
My server.xml
connectors:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<Connector port="80" protocol="HTTP/1.1"
URIEncoding="UTF-8"
connectionTimeout="20000"
proxyName="www.myapp.org"
redirectPort="443" />
<Connector port="443" SSLEnabled="true"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" scheme="https" secure="true"
proxyName="www.myapp.org"
URIEncoding="UTF-8"
compression="on"
compressionMinSize="2048"
noCompressionUserAgents="gozilla, traviata"
compressibleMimeType="text/html,text/xml,text/plain,text/javascript,text/css,application/json" >
<SSLHostConfig certificateVerification="none"
sslProtocol="TLS" >
<Certificate certificateFile="conf/www_myapp_org.crt"
certificateKeyFile="conf/myapp.org.key" />
</SSLHostConfig>
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"
compression="on"
compressionMinSize="2048">
</UpgradeProtocol>
</Connector>
|
My web.xml
security constraint:
XML
1
2
3
4
5
6
7
8
9
10
|
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Context</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
|
Jetty Configuration
In this case, I create a Java keystore containing the server private key and the full certificate chain (my cert comes first in the cert file).
This is a 2-step process:
Step 1: create a PKCS-12 keystore file containing the key and certs:
1
2
3
4
5
6
7
|
openssl pkcs12 -export \
-in www_myapp_org.crt \
-inkey myapp.org.key \
-name myapp.org \
-out myapp-PKCS-12.p12
Enter Export Password: [p/w here]
|
Step 2: Import the above .p12
keystore file into a new Java .jks
keystore file using the Java keytool
command:
1
2
3
4
5
6
7
8
9
10
|
keytool -importkeystore \
-srckeystore myapp-PKCS-12.p12 \
-srcstoretype PKCS12 \
-destkeystore myapp.jks
Importing keystore myapp-PKCS-12.p12 to myapp.jks...
Enter destination keystore password: [p/w here]
Enter source keystore password: [p/w here]
Entry for alias myapp.org successfully imported.
Import command completed: 1 entries successfully imported, 0 entries failed or cancelled
|
(Maybe you can do this in one step but I did not figure that out. I needed to create the PKCS 12 file first using openssl
, before creating the Java keystore using keytool
.)
UPDATE:
It turns out that from Java 9 onwards, you can use the PKCS 12 file (from step 1 above) directly, without needing to perform step 2.
From the keytool documentation:
In JDK 9 and later, the default keystore implementation is PKCS12
.
The proprietary Java Keystore format (.jks
) can still be used.
END of UPDATE
My Jetty is embedded and I configure it programmatically, in my case (not via XML):
Java
1
2
3
4
5
6
7
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
...
SslContextFactory sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(props.getProperty("myapp.keystore.path"));
sslContextFactory.setKeyStorePassword(props.getProperty("myapp.keystore.pass"));
|