Distributed Systems¶

2021/22¶

Lab 9

Nuno Preguiça, Sérgio Duarte, Dina Borrego, João Vilalonga

Goals¶

In the end of this lab you should be able to:

  • Understand what is HTTPS and SSL/TLS
  • Know how to develop a REST server using https in Java
  • Know how to develop a SOAP server using https in Java
  • Know how to modify your REST clients to use https
  • Know how to modify your SOAP clients to use https
  • Know how to generate a keystore with server cryptographic keys
  • Know how to generate a truststore with root certificates and the certificate for your server

TLS / SSL¶

TLS is a cryptographic protocol for securing communications over TCP.

TLS provides:

  • Privacy - data streams are encrypted;
  • Integrity - data streams are protected against tampering;
  • Autentication - identity of servers and clients (optionally) is asserted.

HTTPS¶

HTTPS is the protocol that results from the exchange of HTTP messages on top of TLS (secure) connections.

TLS provides to HTTPS: Privacy, Integrity and Autentication.

HTTPS - Protocol overview¶

The server has a (password protected) keystore holding its public key certificate and the corresponding private key.

The client has a (password protected) truststore holding root CA certificates and assorted server certificates. These are trusted implicitly. Every other certificate is only trusted after validating the entire certificate chain.

Upon client connection, the server presents its certificate.

If the server certificate passes validation, the client challenges the server to prove its identity. To respond to the challenge successfully, the server needs to use its private key. By the end, of the process, client and server share a secret key that will be used to encrypt all traffic exchanged for the rest of the session.

REST Server and HTTPS¶

static final int PORT = 8080;
static final String SERVER_URI_FMT = "https://%s:%s/rest";

var config = new ResourceConfig();
config.register(UsersResource.class);

var ip = InetAddress.getLocalHost().getHostAddress();
var serverURI = URI.create(String.format(SERVER_URI_FMT, ip, PORT));
JdkHttpServerFactory.createHttpServer( serverURI, config, SSLContext.getDefault());

Two changes are needed:

  • The server URI needs to be https.
  • The server needs to be created with a TLS/SSL context.

SOAP Server and HTTPS¶

static final int PORT = 8080;

var ip = InetAddress.getLocalHost().getHostAddress();       

var server = HttpsServer.create(new InetSocketAddress(ip, PORT), 0);

server.setExecutor(Executors.newCachedThreadPool());        
server.setHttpsConfigurator(new HttpsConfigurator(SSLContext.getDefault()));

var endpoint = Endpoint.create(new SoapUsersWebService());      
endpoint.publish(server.createContext("/soap"));

server.start();

The SOAP endpoint needs to be created and then published to a HTTPS server.

The server needs to be configured to use a TLS/SSL context.

ERRATA:

Ao código acima, foi adicionada a linha:

server.setExecutor(Executors.newCachedThreadPool());

Sem esta linha, o servidor apenas atende um pedido de cada vez.

REST/SOAP Clients and HTTPS¶

Normally, nothing is required to use https client-side.

However, when servers use insecure self-signed certificates, the default validation procedure will fail.

To override the default validation procedure (and risk it), the minimal requirement is to set the global HostnameVerifier, like so:

HttpsURLConnection.setDefaultHostnameVerifier(new InsecureHostnameVerifier());

Used once and before the first request.

public class InsecureHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname, SSLSession session) {
        return true;  
    }
}

HTTPS Client Execution¶

Normally, clients are invoked as usual...

However, a truststore is needed when clients call insecure servers, which have self-signed certificates.

java -Djavax.net.ssl.trustStore=<truststore-filename> 
        -Djavax.net.ssl.trustStorePassword=<truststore-password> -cp ... <classname>

HTTPS REST/SOAP Server Execution¶

Servers require the location of the keystore file used to populate the TLS/SSL context.

The keystore is password protected, so the password to open the keystore is also needed.

java -Djavax.net.ssl.keyStore=<keystore-filename> 
        -Djavax.net.ssl.keyStorePassword=<keystore-password> -cp ... <classname>

For servers that are also clients, both the keystore and truststore are needed.

java -Djavax.net.ssl.keyStore=<keystore-filename> 
        -Djavax.net.ssl.keyStorePassword=<keystore-password> 
        -Djavax.net.ssl.trustStore=<truststore-filename> 
        -Djavax.net.ssl.trustStorePassword=<truststore-password> -cp ... <classname>

Keytool¶

Java comes with keytool - a CLI utility to manage keystores and truststores.

Can be used to generate public/private key pairs and add to keystores,
export public key certificates, and import them into truststores.

Private Key generation.¶

To create a public/private key pair use:

 keytool -genkey -alias <server-name> -keyalg RSA -validity 365 -keystore <keystore-filename> -storetype pkcs12

This generates a new key pair for a server: <server-name>, which is stored in keystore: keystore-filename

The program will ask for a password, either to create the keystore or to open it for modification.

Self-signed Server Certificate¶

To export a self-signed certificate for a server <server-name>, whose public/private key pair is already present in a keystore, use:

keytool -exportcert -alias <server-name> -keystore <keystore-filename> -file <file-certificate>

Again, the command will prompt for the password of the keystore to be able to open it.

CACERTS¶

The default Java truststore cacerts contains just a list of root CA certificates.

These are certificates issued by "Certification Authorities" that Java trusts implicitly.

They are stored in a file named cacerts included in every JDK and JRE distribution.

The default cacertspassword is changeit.

Truststore¶

A truststore is a collection of trusted certificates.

To accept self-signed certificates, add them to a truststore, like so.

keytool -importcert -file <file-certificate> -alias <server-name> -keystore <truststore-filename>

Again, the command will prompt for the password to be able to open the truststore.

Note that for keytool, a truststore is just a special kind of keystore, that stores certified public keys (certificates).

Client Truststore¶

If a client needs to access both insecure servers and secure services,
such as Dropbox ou Google drive, it will need to use a modified cacerts truststore.

For that, make a copy of cacerts and add the self-signed certificates using keytool, as describeb above.

EXERCISES¶

  1. Try the sample code.
  2. Delete the provided keystore and truststore files. Create new ones using keytool.
  3. (Optional) If using Linux...
    • Study the provided gen_certificates.sh script.
    • Extend it to automate the generation of keystores and truststores for your servers.
  4. Modify the other clients and servers of your project to use HTTPS.