This article will take you through the set up of a web
server to accept HTTPS connections with a self-signed certificate.
Technically, HTTPS is not a protocol in and
of itself; rather, it is the result of simply layering the Hypertext Transfer
Protocol (HTTP) on top of the SSL/TLS protocol, thus adding the security
capabilities of SSL/TLS to standard HTTP communications.
The security of HTTPS is therefore that of
the underlying TLS/SSL, which uses long term public and secret keys to exchange
a short term session key to encrypt the data flow between client and server.
TLS authentication uses X.509
certificates—a common, secure and reliable method of authenticating your
application objects.
Common filename extensions for X.509 certificates are:
- .pem – (Privacy-enhanced Electronic
Mail) Base64 encoded DER certificate, enclosed between "-----BEGIN
CERTIFICATE-----" and "-----END CERTIFICATE-----"
- .cer, .crt, .der – usually in binary DER form, but
Base64-encoded certificates are common too (see .pem
above)
- .p7b, .p7c –PKCS#7 SignedData structure
without data, just certificate(s) or CRL(s)
- .p12 – PKCS#12, may contain
certificate(s) (public) andprivate keys(password protected)
- .pfx – PFX, predecessor of PKCS#12
(usually contains data in PKCS#12 format, e.g., with PFX files generated
in IIS)
PKCS#7 is a standard for signing or encrypting (officially
called "enveloping") data. Since the certificate is needed to verify
signed data, it is possible to include them in the SignedData structure. A .P7C file is a
degenerated SignedData structure, without any data to sign.
PKCS#12 evolved from the personal information exchange (PFX) standard and is used to
exchange public and private objects in a single file.
There
are different ways of creating a self-signed certificate, such as using Java
keytool. I prefer openSSL because the keys and certificates generated this way
are more standardized and can be used for other purposes.
Lets proceed to generate both server and client
certificates for use with mutual authentication (Two-Way SSL).
1.
Create private keys using OpenSSL
a. openssl genrsa -out server-private.pem 2048
b. openssl genrsa -out client-private.pem 2048
The private keys are 2048 bits long and generated using the RSA algorithm. They are not protected with an additional pass phrase. names of the private keys are server-private.pem and client-private.pem
2.
Create
self-signed X509 certificates
a.
openssl req -new -x509 -key
server-private.pem -out
server-certificate.pem -days 365
b.
openssl req -new -x509 -key
client-private.pem -out
client-certificate.pem -days 365
For each command you will be prompted to
enter a few pieces of information, use “.” if you wish to leave the field
blank.
1
|
Country Name (2 letter
code) []:
|
2
|
State or Province Name (full name)
[]:
|
3
|
Locality Name (eg, city)
[]:
|
4
|
Organization Name (eg, company)
[]:
|
5
|
Organizational Unit
Name (eg, section) []:
|
6
|
Common Name (eg, YOUR name)
[]: HOSTNAME
|
7
|
Email Address []:.
|
The field Common Name is quite important
here. It is the hostname of the machine you are trying to certify with the
certificate, which is the name in the DNS entry corresponding to your machine
IP.
3.
Create JKS
trust stores
a.
keytool -importcert
-trustcacerts -keystore server_truststore.jks -storetype jks -storepass <server_truststore_password> -file client-certificate.pem
b. keytool -importcert -trustcacerts -keystore client_truststore.jks -storetype jks -storepass <client_truststore_password> -file server-certificate.pem
4.
Create PKCS12
keystores and import the certificates
Java’s keytool application will not let
us import an existing private key into a keystore. The workaround to this
problem is to combine the private key with the certificate into a pkcs12 file
and then import this pkcs12 keystore into a regular keystore.
a. openssl pkcs12 -export -inkey server_private.pem -in server-certificate.pem -out server.p12
b. openssl pkcs12 -export -inkey client_private.pem -in client-certificate.pem -out client.p12
5.
Convert the
PKCS12 keystores to Java keystores using Java keytool
a. keytool -importkeystore -srckeystore server.p12 -srcstoretype pkcs12 -destkeystore server.jks –deststoretype jks
b. keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.jks –deststoretype jks
Keytool will first ask you for the new
password for the JKS keystore twice, and it will also ask you for the password
you set for the PKCS12 keystore created earlier.
1
|
Enter destination
keystore password:
|
2
|
Re-enter new password:
|
3
|
Enter source keystore password:
|
4
|
Entry for alias
1 successfully imported.
|
5
|
Import command completed: 1
entries successfully imported, 0 entries
failed or cancelled
|
It will output the number of entries successfully imported,
failed, and cancelled.
If nothing went wrong, you should have 2 new keystore files:
server.jks & client.jks.
6.
Configure
server
Depending on how you are using your
keys, you will now need to configure your server. The file server.jks contains your servers
self signed certificate, and the file server_truststore.jks
contains your servers trust store that trusts your client certificate.
Below is the code snippet on configuring ssl
context factory in jetty.
private SslContextFactory constructSslContextFactory(final String password, final String keystorePath) throws IOException {
final SslContextFactory sslFactory = new SslContextFactory();
sslFactory.setKeyStorePassword(password);
sslFactory.setKeyManagerPassword(password);
//sslFactory.setKeyStoreType("PKCS12");
//sslFactory.setTrustStoreType("PKCS12");
sslFactory.setTrustStorePassword(password);
sslFactory.setNeedClientAuth(false);
//sslFactory.setAllowRenegotiate(false);
relaxSslTrustManager();
if (ObjectUtils.isNull(keystorePath)) {
final URL keyURL = this.getClass().getResource("/ssl/localhost.jks");
final Resource keyStoreResource = Resource.newResource(keyURL);
sslFactory.setKeyStoreResource(keyStoreResource);
return sslFactory;
}
sslFactory.setKeyStorePath("${server keystore Path}");
sslFactory.setTrustStore("${server TrustStore Path}");
return sslFactory;
}
7.
Configure
client
Depending on how you are using your keys, you
will now need to configure the client. The file client.jks contains your servers self signed
certificate, and the file client_truststore.jks
contains your clients trust store that trusts your server certificate.If your
are going to be using a browser as the client, then you will want to import the
client.p12 file into your
browser.
Below is the code snippet on configuring the
keystore and truststore in JAVA.
KeyStore trustStore = KeyStore.getInstance("PKCS12");
//KeyStore trustStore = KeyStore.getInstance("jks");
File file = new File("${client pk12 file}");
//File file = new File("${clientkeystore Path}");
if(!file.isFile()) {
if(logger.isInfoEnabled()) {
logger.info("File not found "+file.getAbsolutePath());
}
return;
}
FileInputStream instream = new FileInputStream(file);
try {
trustStore.load(instream, "password".toCharArray());
} finally {
instream.close();
}
//KeyStore trustStore = KeyStore.getInstance("PKCS12");
KeyStore trustStore_1 = KeyStore.getInstance("jks");
File file_1 = new File("${client truststore Path}");
if(!file_1.isFile()) {
if(logger.isInfoEnabled()) {
logger.info("File not found "+file.getAbsolutePath());
}
return;
}
FileInputStream instream_1 = new FileInputStream(file);
try {
trustStore_1.load(instream_1, "password".toCharArray());
} finally {
instream.close();
}
gContext = provideSSLContext(trustStore, null, "password".toCharArray());
If your application uses apache camel, with that we cannot load the java keystore as described above. Hence, load
the (PKCS12) key using apace camel context and run the java installcert tiny
application.
You need to run installCert with host name and IP or with the domain name. It will generate jssecacerts keystore. copy this to the $JAVA_HOME\jre\lib\security.
Restart your server and you should be able to handle https calls with a self signed certificate.