This article is part 1 of a four part series where we look at the issues around developing secure applications. Thousands of hackers work hard to break into our applications try to phish for user information or implant malware. This means as responsible and professional application developers we need to be vigilant about application security to protect users. There are a range of techniques and practices we can employ to enable and enhance application security. In this four part series we will cover at a high level the conceptual basis for these techniques and provide simple source code to illustrate the concepts in a practical way.
In this first part we will look at the Secure Socket Layer (SSL).
The source code for this article can be found here.
Overview
Any application connected to the Internet, such as a web application or client, an industrial control systems or an Automotive application, whatever the nature of an Internet connected application it will be vulnerable and exposed to online threats such as viruses, Denial of Service attacks and targeted application or machine compromise attacks..
These threats may come from those seeking to inflict mischievous damage, make money, or Sabotage infrastructure remotely. Best practice, and indeed national regulatory standards such as North American Electric Reliability Corporation (NERC) mandates a strict security. This applies to embedded devices found in industrial and government infrastructure and presents an emerging threat since many devices used in control systems do not support default authentication.
Many programming languages such as Java have strong security policies and implementation., however in the connected space of the internet data in transit is vulnerable to a range of attacks. Using a secure language like Java we can create secure data transfers using Public-key cryptography however this form of data security is vulnerable to a man-in-the-middle attack (MITM).
Introduction to Transport Layer Security (TLS).
We can protect to a very high degree against a MITM security breach for Public-key encrypted data by following the SSL/TLS standard particularly section 7.4.8. What follows is a very simple outline of what is described in section 7.4.8.
SSL Certificates
SSL Certificates are an extension to the Public-key encryption that include the attribute of identity. This identity can be verified by what is known as a Certificate authority (CA) or signing authority, hence these certificate are sometimes referred to as ‘signed’ or ‘digitally signed’. This signature is a confirmation or validation by the CA that the public key contained in the certificate belongs to the entity presenting the certificate. Generally you buy these certificated from a trusted provider however it is also possible to create them yourself, such certificates are often referred to as self-signed.
SSL/TLS Handshake
In the context of the classic client server connection we can use the secure http protocol https which implements the SSL/TLS standard. To initiate this connection over SSL/TLS we perform what is known as the SSL/TLS handshake. This procedure follow the following pattern. A client shows a certificate and uses it as part of a Certificate Verify message (as described in section 7.4.8), and the server successfully validates the client certificate with regards to a set of valid attributes such as a private contained in the trust/key stores.
If the server requests a valid certificate then the client has certainty that as long as the request did not originate from a fake server any further data exchange will be secure to the extent of the Public-key encryption.
If the client presents a valid certificate then the server has a guarantee that it is talking to the right client (the one identified by the client certificate).
Learn by example
What follows is an introduction to using the concepts presented in a practical scenario. We will build a web server and client, then by generating self-signed certificates perform the SSL/TLS handshake to illustrate the principals involved and start to build a vocabulary for all the many details involved in implementing the concepts.
The certificates
Certificates are related to public key cryptography by containing/wrapping a public key. This public key is paired with a private key. The private key will reside on the server in a keystore.
The easiest way to get started is to use the java Keytool to generate a keystore and self-signed certificate with a private key, then using the play frameworks developer friendly resources easily establish a secure http protocol connection from the client to the play server.
Step 1 – make the keystore, private key and certificate for the public key
keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass replacethis -validity 360 -keysize 2048
Step 2 – export the certificate so the client can use it to authenticate
keytool -export -alias selfsigned -file mycert.cer -keystore keystore.jks
now you should have the following files, a keystore for the play server “keystore.jks“ and a certificate for the client “mycert.cer” as shown below. We will use these in the source code.
The Server
We will use the Play Framework to build simple play server with ssl configuration. The Play framework is chosen to code the server due to its excellent SSL integration.
Step 1
Install the latest version of the Simple Build Tool sbt for your operating system from here.
Step 2
You need to copy the “keystore.jks“keystore for the play server into the PlayServer/conf directory as shown below
Step 3 Build the server
We only need the Simple Build Tool (sbt) to build the Play server.
Change into the Play Server directory and issue the following sbt build commands from a terminal.
sbt clean compile
The first time you build the code it takes a while for sbt to download all the play framework dependencies, however subsequent builds are faster
Step 4
Build the server uber jar with the sbt one jar task.
sbt one-jar
in the “PlayServer/target/scala-2.10/” directory you should see the eduonixssl_2.10-1.0-one-jar.jar uberjar as shown below
Copy this and rename it to something useful like “eduonixssl.jar”. There is an Ant file that will do this and output to a staging directory if you are ok with ant (see the Eduonix java build tools blog for more information on how to automate routine build tasks with ant).
Step 5
Run the server
In the directory where you copied and renamed the uber jar you can run the server with
java -jar eduonixssl.jar
The client
We will use the Apache HttpComponents™ project to build a client with ssl configuration.
You need to copy the “mycert.cer” certificate for the client into the src/main/resources directory as shown below
Perform the SSL/TLS handshake
Step 1
Run the play server and you see it creates the keystore in the same directory as the jar as well as a logs directory and a RUNNING_PID file
Step 2
Run the client main class EntryPoint.java in your ide for convenience you should see the output of the ssl/tls handshakke below.
Then the secure https get request followed by some html
Then the play server reports the secure connection can be kept alive for further requests
this exercise was useful as it illustrated the following
- The Play Framework is a good rapid application environment for creating a rest api
- Apache Httpcomponents is good rapid application environment for creating a client
- Configuring the Play Framework server with the “jks“ containing the private key and client certificate for authentication was trivial
- Creating the ssl/tls connection to the play server and presenting the “mycert.cer” certificate for authentication was more code but compared to other frameworks was simple.
We will now step through the key parts of the source code that facilitated the ssl/tls handshake.
Key SSL/TLS concepts in the Play Framework Rest Server Codebase
Now we will look at the key play code that configures the ssl/tls connector.
We place the certificate in the Play server conf directory. Then in the servers EntryPoint
Class we simply set the following system properties.
First we set the secure and open http ports
System.setProperty("http.port", "9001"); System.setProperty("https.port", "9443");
Then we test for the presence of a Keystore, if one exists we use it otherwise copy in the new updated store
File file = new File("keystore.jks"); if(!file.exists()){ InputStream is = EntryPoint.class.getResourceAsStream("keystore.jks"); File keystore = new File("keystore.jks"); Files.copy(is, keystore.toPath(), StandardCopyOption.REPLACE_EXISTING); Logger.info("Keystore does not exist locally. Copying into local directory."); } else{ Logger.info("Keystore exists locally. Using local keystore."); }
Once we have set up the keystore we set system properties for its location and password
System.setProperty("https.keyStore", "keystore.jks"); System.setProperty("https.keyStorePassword", "replacethis");
Now the Play frameworks Netty server is configured for ssl/tls.
Key SSL/TLS concepts in the Apache HttpComponents™ Client Codebase
The EntryPoint class calls the rest server via a secure ssl/tls rest client.
SSLManager sslConnection = new SSLManager(); sslConnection.doGet( );
Unlike the play server framework we need to write more code to create our own secure rest client we do this in the SSLManager class. This class creates an ssl/tls connection to the server with an instance of the CloseableHttpClient from the Apache HttpComponents™ project. CloseableHttpClient is the base class of the httpclient library, you can read more about the relationship between the various artifacts of here
CloseableHttpClient </strong><strong>client = HttpClients.<em>custom</em>() .setSSLSocketFactory(sslsf) .setDefaultCookieSpecRegistry(r) .setDefaultRequestConfig(requestConfig) .build();
We construct our secure client using the Factory methods found in the HttpClients class. To use this client factory we must create the following types
- SSLSocketFactory to validate the identity of the HTTPS server
- CookieSpecProvider for Cookie management
- RequestConfig for tls configuration
First we create a certificate factory and parse the certificate and check the format, this is a critical step, if we are tricked into loading a fake certificate we are basically hacked.
CertificateFactory cf = CertificateFactory.<em>getInstance</em>(<strong>"X.509"</strong>); InputStream caInput = SSLManager.<strong>class</strong>.getClassLoader().getResourceAsStream(<strong>"mycert.cer"</strong>); Certificate ca = cf.generateCertificate(caInput);
Then we create a trustmanager and a SSL context
<em>// Create a TrustManager that trusts the CAs in our KeyStore</em> String tmfAlgorithm = TrustManagerFactory.<em>getDefaultAlgorithm</em>(); TrustManagerFactory tmf = TrustManagerFactory.<em>getInstance</em>(tmfAlgorithm); tmf.init(keyStore); <em>// Create an SSLContext that uses our TrustManager</em> SSLContext context = SSLContext.<em>getInstance</em>(<strong>"TLS"</strong>); context.init(<strong>null</strong>, tmf.getTrustManagers(), <strong>null</strong>); SSLContext sslcontext = SSLContexts.<em>custom</em>() .loadTrustMaterial(keyStore, <strong>new </strong>TrustSelfSignedStrategy()) .build();
Now we are in a position to set up the SSLSocketFactory
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[]{"TLSv1"}, null, new HostnameVerifier() { public boolean verify(String s, SSLSession sslSession) { return s.equals(<em>HOST_NAME</em>); } });
Now we follow similar steps using builders for the CookieSpecProvider and RequestConfig types. From a security perspective these are less critical, the key security vulnerability here is the integrity of the CertificateFactory code block.
Certificate ca = cf.generateCertificate(caInput);
Now we have successfully configured the secure client we can use it for rest calls to the rest server.
HttpGet get = new HttpGet(BASE_URL); CloseableHttpResponse closeableHttpResponse = closeableHttpResponse = client.execute(get);
Hopefully if you are new to coding rest applications this code base and article can be used as a guide and bootstrap code for building a secure rest application. Along the way we have introduced you to the Play framework and the Simple Build Tool.
Summary
This article and coding exercise was just an overview and introduction to the terminology and basic ideas. Then we worked through some simple code to implement the ideas and illustrate the concepts.
For professional practice you need to go a lot further due to the prevalence of hostile agents and the security of you or your client’s data. For example at a basic minimum you should check whether a certificate has been issued by a trusted source instead of just considering whether it is currently valid, you can easily check whether a certificate was self-signed as self-signed certificates will always fail OpenSSL’s validation.
The terminology of SSL Certificates is extensive. Certificates can contain extensions such as Subject Alternative Names (SAN) which allow you to specify a list of host names to be protected by a single SSL certificate. This is important as certificates obtained from a CA are expensive and only last for a set time period.
This concludes our introduction to securing an application with SSL/TLS. In the Part 2 we’ll look at how an application can authenticate their users across websites and apps without having to own and manage password files using OpenID from the OpenID Foundation.