Wednesday, 16 April 2014

Mutual SSL Autentication with a self signed certificate in JAVA



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.


No comments:

Post a Comment