If you are using SSL in the wild you’ll probably generate your certificate on letsencrypt.org and all is pretty much taken care of.

But what if you have an internal HAProxy serving requests on the 192.168.x.x scope? Or you have an internal Spring Boot webapp that you also want to secure? As the servers will not be accessible by the outside world, you will not be able to generate a certificate for them. Don’t let that stop you. It’s trivial to generate your own certificates and install them in company resources including iOS devices.

The suggested path is to create an internal Certificate Authority (CA) and add that source of trust to all the machines that will be accessing the services secured.

Bird’s eye view of the process:

Authority: will act as the source of trust for all certificates you sign. You will have to install the Authority on every single machine/phone you’ll want.

  1. Generate a private key for a Certificate Authority (CA)
  2. Generate a Certificate for the Certificate Authority (CA)
  3. Install Certificate Authority on Windows
  4. Install Certificate Authority on iOS

Client: we can issue private keys for all our projects inside our network. Those private keys will be validated by our own generated and installed authority.

  1. Generate a private key for the client
  2. Generate a Certificate Sign Request (CSR)
  3. Have CA sign the CSR thus generating the client Certificate
  4. Merge the client certificate and the CA certificate into a pkcs12 file which is read by Spring

Install OpenSSL

First things first, install OpenSSL. If you are on a Linux machine you can use the distro repository and do something like apt-get install openssl but if you are on windows things are a little trickier. OpenSSL states on their Wiki the following binary distributions by third parties. It’s always a risk to install software from sources you don’t trust, and you could compile OpenSSL on your machine, but I personally used https://indy.fulgan.com/SSL.

You can then just unzip the files into any folder and use the openssl.exe from there.

You must also create a configuration file, can be called openssl.cnf. In it’s most basic form it can take just the following variables:

# minimum config for openssl

# conf for the `req` command, notice that it reads values from dn_prompt
[req]
distinguished_name = dn_prompt
prompt = yes

# the only three required, you'll be prompted to change values
[dn_prompt]
commonName         = Common Name
commonName_default = Your Project Name
countryName         = Country Name
countryName_default = UK
localityName         = City
localityName_default = London

Generate Certificate Authority

We start by generating a private key for the authority:

openssl genrsa -des3 -out ca_key.key 2048

And we then generate two certificates. Notice that the config value should point to wherever you placed your openssl.cnf file. Also notice that we used 1825 days, 5 year as it’s a round number. Any other value will do. But on certificates Apple enforces tighter limits which we cover bellow.

openssl req -config c:\openssl.cnf -x509 -new -nodes -key ca_key.key -sha256 -days 1825 -out ca_cert.pem
openssl req -config c:\openssl.cnf -x509 -new -nodes -key ca_key.key -sha256 -days 1825 -out ca_cert.crt

You now have three files. The ca_key.key (private key) and the ca_cert.pem and ca_cert.crt which are the certificate files for your certificate authority.

Install on Windows: Click the ca_cert.crt file on Windows and follow screen instructions. Then click Start -> Run -> certmgr.msc. It will open the Windows Certificate Manager. You will find the certificate you installed under “Intermediate Certification Authorities”. You’ll want to drag that file to “Trusted Root Certification Authorities”. This can be done as a non admin user.

Install on iOS: Email the ca_key.pem file to yourself. Open the email on iOS using the Apple Mail App. Follow the instructions and certificate will be installed. To uninstall you can go to Settings -> General -> Profile. After proper installation iOS requires a second step for you to trust the certificate, you must go to Settings -> General -> About -> Certificate Trust Settings and Enable Full Trust For Root Certificate.

Done. That’s all there is about generating a proper local CA.


Generate Certificates for services

Start by generating a private key for the service/site/etc.

openssl genrsa -des3 -out service1_key.key 2048

Generate a CSR (Certificate Sign Request):

openssl req -new -key service1_key.key -out service1_sign_request.csr

Now that we have the website key and the certificate sign request we need to create an external file with the names/ip’s for which such certificate will be valid. Create a file called service1_config.ext with the following info:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

# you can have both DNS and IP; listed a few just as an example
[alt_names]
DNS.1 = localhost
DNS.2 = mywebsite
DNS.3 = mywebsite.local
IP.1 = 10.1.1.3
IP.2 = 127.0.0.1

Now we’ll use the CA certificate and private key together with the CSR (Certificate Sign Request) and the config file to generate a proper certificate for the website. Since iOS 13 Apple only allows a max of 825 days on certificates so that’s what we’ll use, also notice that Apple just recently announced that limit going down to 398 days so you may need to adjust accordingly depending on when you read this.

openssl x509 -req -in service1_sign_request.csr -CA ca_cert.pem -CAkey ca_key.key -CAcreateserial -out service1.crt -days 825 -sha256 -extfile service1_config.ext

You’ll now have the following files:

ca_key.key                - certificate authority private key  
ca_key.pem                - certificate authority certificate pem format
ca_key.crt                - certificate authority certificate crt format
service1_key.key          - website private key  
service1_sign_request.csr - website certificate sign request  
service1_config.ext       - website config file for openssl sign request  
service1.crt              - website certificate crt format

The one that matters, since CA Authority is already installed in all the devices is the certificate service1.crt.


Spring Boot or HAProxy

Spring Boot uses PKC12 files.
HAProxy uses pem files.

Let’s create both those files:

# PCK12 (Public-Key Cryptography Standards 12)
openssl pkcs12 -export -in ca_key.crt -inkey ca_key.key -in service1.crt -inkey service1_key.key -name service1 -out service1.p12

# pem (Privacy Enhanced Mail Certificate file)
openssl pkcs12 -in service1.p12 -nodes -out service1.pem

Spring Boot – edit application.properties and insert something like this:

server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate, place it src/main/resources
server.ssl.key-store=classpath:service1.p12
# The password used to generate the certificate
server.ssl.key-store-password=PASSWORD-USED
# The alias mapped to the certificate (the -name service1 on the last command)
server.ssl.key-alias=service1 
# force SSL 
security.require-ssl=true

HAProxy – edit config file and insert something like this:

frontend service1
    bind 10.1.1.3:443 ssl crt /etc/ssl/certs/service1.pem
    default_backend service1_web_servers

And that’s it, SSL for internal projects without the warning “this site is insecure” or “certificate not valid” error messages.


Things that may be useful:

Remove password from private key:
If you’re planing on running some services, like HTCondor, you may need to have private decrypted keys. This can easily be achieved by running:

openssl rsa -in [my_private.key] -out [my_private.key]

Inspect Private Keys, CSR’s, CRT’s and PKCS’s:
At any point you may need to inspect any of these. Commands below:

# inspect a CSR (Certificate Signing Request)
openssl req -text -noout -verify -in [my.csr]

# inspect a private key
openssl rsa -in [my_private.key] -check

# inspect a CRT (Certificate)
openssl x509 -in [my.crt] -text -noout

# inspect a PKCS12 
openssl pkcs12 -info -in [keyStore.p12]