Transport Layer Security (TLS) Self-Signed Certificates
Self-signed server TLS certificates are useful for testing server TLS configuration or for personal use when encrypting communication over HTTP.
These types of certificates are considered untrustworthy because the certificate identity has not been signed/verified by a third party certificate authority (CA). Otherwise, a self-signed certificate still ensures that communication over HTTPS is encrypted.
For long term server use, Sonatype recommends getting a certificate signed by a CA.
Generating Self Signed Server TLS Certificates
The following steps use Oracle Java 7+ keytool (Unix/Windows) to generate self-signed server certificates which can be used with Sonatype server products.
Openssl is needed only when creating certificates for use in a reverse proxy such as Apache or nginx.
-
Generate public private key pair using keytool:
keytool -genkeypair -keystore keystore.jks -storepass password -alias example.com \ -keyalg RSA -keysize 2048 -validity 5000 -keypass password \ -dname 'CN=*.example.com, OU=Sonatype, O=Sonatype, L=Unspecified, ST=Unspecified, C=US' \ -ext 'SAN=DNS:nexus.example.com,DNS:clm.example.com,DNS:repo.example.com,DNS:www.example.com'
Output: keystore.jks
-
Generate PEM encoded public certificate file using keytool:
keytool -exportcert -keystore keystore.jks -alias example.com -rfc > example.cert
Output: example.cert
-
Convert our Java specific keystore binary".jks" file to a widely compatible PKCS12 keystore ".p12" file:
keytool -importkeystore -srckeystore keystore.jks -destkeystore example.p12 -deststoretype PKCS12
Output: example.p12
(Optional) List and verify new keystore file contents:
keytool -list -keystore example.p12 -storetype PKCS12
-
(Optional) Extract pem (certificate) from ".p12" keystore file ( this is same as step 2, but openssl spits out more verbose contents ):
openssl pkcs12 -nokeys -in example.p12 -out example.pem
Output: example.pem
-
Extract unencrypted private key file from ".p12" keystore file:
openssl pkcs12 -nocerts -nodes -in example.p12 -out example.key
Output: example.key
Configuring SSL Server Certificates
Sonatype Nexus
Configuring Nexus and Reverse Proxies
Eclipse Jetty
Apache httpd
Use either:
SSLCertificateFile "example.pem" SSLCertificateKeyFile "example.key"
or
SSLCertificateFile "example.cert" SSLCertificateKeyFile "example.key"
Nginx
Use either:
ssl_certificate example.pem; ssl_certificate_key example.key;
or
ssl_certificate example.cert; ssl_certificate_key example.key;
What are keystores and truststores?
There are two kinds of key or certificate storage files used by Oracle Java. Oracle has a good reference defining keystores and truststores.
Where does a Java client load trusted certificates from?
A Java client program loads trusted certificates from the following locations, in this order:
- a file specified by the system property
javax.net.ssl.trustStore
. This property is not set by default. If set, but the file does not exist, no truststore is used. - if
java-home/lib/security/jssecacerts
is a valid file, trusted certificates are loaded from here. This file does not exist by default but can be created by a user using keytool. -
java-home/lib/security/cacerts
exists by default. It is pre-loaded with well known public certificate authority root certificates that allow a client program to trust sites which have certificates signed by them. If for some reason it is missing, there will be no trusted certificates loaded into the client.
Oracle provides a summary about Customizing the Default Keystores and Truststores, Store Types and Store Passwords
When does the file ~/.keystore get used?
The keytool program creates or reads this file whenever the -keystore
argument is not provided to the keytool program.
Java client programs do not normally read this file when looking for trusted certificates. This file is intended to hold user specific private keys.
Therefore, importing a remote server certificate into ~/.keystore will not usually resolve issues where trust of the remote server cannot be established . ie. solving PKIX path building failed errors.
Combining Keys and Certificates
If you've received a separate private key, certificate, and root certificate from your certificate provider you will need to combine them in order to use them in a keystore for inbound SSL connections. To do that, you'll need to use the openssl command line tool. That will be available by default in most Linux distributions. For Windows, see here.
openssl pkcs12 -export -in nexus.crt -inkey nexus.key -out nexus.p12 -name nexus -CAfile root.crt -caname root
Then to import the resulting p12 file into a new java keystore:
keytool -importkeystore -deststorepass password -destkeypass password -destkeystore keystore.jks \
-srckeystore nexus.p12 -srcstoretype PKCS12 -srcstorepass password \
-alias jetty
Common keytool Operations
Here are some common keytool operations that are needed when managing SSL certificates.
Always use the full path to your keytool executable and your intended target keystore file when executing keytool. Do this with the -keystore
parameter. This helps avoid confusion about which keystore files are being modified.
Usually you will want the keytool to manipulate the system wide truststore file at java-home/lib/security/jssecacerts
or java-home/lib/security/cacerts
If you are using a system wide default JSSE keystore location on either a Linux,Solaris or OSX platform, you must run the commands as the root user. You can do this either by changing to the root user (su -
) first, or by using the sudo command: sudo [command]
.
On Windows, open a command prompt as an Administrator
.
The default password used by Java for the built-in keystore is changeit
. If your key-store uses a different password, you'll need to specify that password as the -storepass
parameter.
Getting a Remote Certificate
This command connects to a remote server on a specific port and prints the SSL certificate to a file.
keytool -printcert -rfc -sslserver example.com:443 > example.pem
Examining Certificate File Details
To verify the validity of a certificate, you must visually examine the contents in human readable (non-rfc) form. Each certificate in the chain will be demarcated by a line containing Certificate[n]:
, where n
is the order number of the certificate.
keytool -printcert -file example.pem
Getting a Remote Certificate Through A HTTP Proxy Server
Sometimes your HTTP Proxy server may be modifying the remote certificate. In that case it is important that keytool uses the proxy server when fetching the certificate. Use special -J
options to do this.
keytool -J-Dhttps.proxyHost=<proxy_hostname> -J-Dhttps.proxyPort=<proxy_port> -printcert -rfc -sslserver <remote_host_name:remote_ssl_port>
On recent Windows systems and on Gnome 2.x systems it is possible to tell keytool to use the system proxy settings (both these systems let you set proxies globally through their user interface). In that case, use the following:
keytool -J-Djava.net.useSystemProxies=true -printcert -rfc -sslserver <remote_host_name:remote_ssl_port>
Replace <proxy_hostname>
and <proxy_port>
with the HTTP proxy server that Nexus is configured with under Administration -> Server
. Replace <remote_host_name:remote_ssl_port>
with one of the remote host and port having the certification problem. You can omit the port if it is the default 443.
Getting a Remote Certificate of a HTTP Proxy Server
Configuring a client to trust the HTTP proxy server certificate is often much better than trusting every unique remote certificate accessed through the proxy.
Use the command as described in Getting a Remote Certificate Through A HTTP Proxy Server.
Then, examine the certificate and look for the Certificate[n]:
entry that has an Issuer:
line that correlates to your HTTP proxy server. Usually this will be the last certificate.
You can then count that number of entries down, demarcated by -----BEGIN CERTIFICATE-----
and -----END CERTIFICATE-----
lines, in the encoded certificate file, and copy that certificate entirely to a new file ( including the begin and end certificate parts ). The new file then contains only the certificate of your HTTP proxy server.
At this point you may wish to examine it and then import the HTTP proxy certificate using the standard command into a keystore.
Import a Certificate to a Truststore
Once you have the remote certificate, it can be imported into the default JVM truststore using the default store password.
If you are using a specific keystore, change the storepass and keystore used:
keytool -importcert -file example.pem -alias example.com -storepass changeit -keystore $JAVA_HOME/lib/security/cacerts
Explicitly Trusting a Self-Signed or Private Certificate in a Java Based Client
If you generate a self-signed certificate, and want a Java based client to explicitly trust this certificate, then you need to make sure the trust store used your client, trusts at least one member of the certificate chain.
Suppose you have a server at https://example.com using a self-signed or private certificate:
- (Required) Get the certificate from the server into a PEM encoded file on your Java client host:
keytool -printcert -rfc -sslserver example.com > example.pem
- (Optional/Advised) Inspect the certificate you just downloaded to verify it looks OK:
keytool -printcert -file example.pem
- (Required) Import the certificate into the default Java truststore location under a relevant alias, using the default truststore password:
keytool -importcert -file example.pem -alias example.com -storepass changeit -keystore $JAVA_HOME/lib/security/cacerts
Forcing Apache Maven to Implicitly Trust a Self-Signed Certificate
Apache Maven has a system property maven.wagon.http.ssl.insecure
that can be set to implicitly trust a self-signed certificate from a HTTPS remote repository.
The system property will only work if:
- it is set in the environment variable MAVEN_OPTS
- the remote certificate has a single certificate in the certificate chain ( ie. self-signed)
The property will not work at mvn
invocation time. For example, this will not work: mvn -Dmaven.wagon.http.ssl.insecure=true install
You must set this instead inside the MAVEN_OPTS
environment variable value.
One method to do this explicitly to Maven, is to create a file $HOME/.mavenrc
( or on Windows %HOME%/.mavenrc
) and set MAVEN_OPTS
in there. This file will be sourced every time you invoke Maven.
Forcing Apache Maven to Trust A Certificate Issued by An Organizational Certificate Authority
When your organization has a private certificate authority issuing server certificates, a common problem is that the system property maven.wagon.http.ssl.insecure
will not help. This is because the certificate chain used by the Nexus HTTPS connection contains more than one certificate. The certificate chain hierarchy might look something like this:
root CA (root organizational certificate authority) - sub-org CA 1 (sub-organizational certificate authority) - sub-org CA 2 (sub-organizational certificate authority) - Nexus server certificate
Each branch in the tree is a certificate - so this chain contains 4 certificates.
The Maven property checks if the chain contains only one certificate, which implies it is self-signed. If it contains more than one as above, and none of the other certificates are in the Java trust store used by the Java process running Maven, then the only workarounds are to explicitly import the server certificate into the default truststore or have the Nexus server certificate chain be signed by a public certificate authority already in the default Java trust store.
Querying Remote SSL Protocol and Cipher Support
Some secure connection problems may occur because the remote does not support a protocol or cipher needed by the client. There is a tool called nmap
you can use to see what protocols are supported by the remote.
Note: There is known issue with nmap 7.7 and 7.8 that means no output will be seen. Either nmap 7.6 or earlier needs to be used, or the relevant script patched as per: https://github.com/nmap/nmap/issues/1187#issuecomment-587031079
Below is an example command and output that tests a secure connection to localhost:8453
:
nmap --script +ssl-enum-ciphers -p 8453 localhost Starting Nmap 6.47 ( http://nmap.org ) at 2015-11-20 11:40 AST Nmap scan report for localhost (127.0.0.1) Host is up (0.00013s latency). PORT STATE SERVICE 8453/tcp open unknown | ssl-enum-ciphers: | TLSv1.0: | ciphers: | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_RSA_WITH_AES_128_CBC_SHA - strong | compressors: | NULL | TLSv1.1: | ciphers: | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_RSA_WITH_AES_128_CBC_SHA - strong | compressors: | NULL | TLSv1.2: | ciphers: | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - strong | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - strong | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - strong | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - strong | TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_RSA_WITH_AES_128_CBC_SHA - strong | TLS_RSA_WITH_AES_128_CBC_SHA256 - strong | TLS_RSA_WITH_AES_128_GCM_SHA256 - strong | compressors: | NULL |_ least strength: strong Nmap done: 1 IP address (1 host up) scanned in 0.23 seconds