HTTPS Certificates for Evaluating and Testing the Local License Server

HTTPS Certificates for Evaluating and Testing the Local License Server

Introduction

In most cases, communication between client devices and the FlexNet Embedded local license server need not be secure. However, in deployments where security is required, the local license server can be configured to support exchanges with the client devices over a secure HTTPS connection. Enabling HTTPS mode in the local license server requires a server certificate, purchased from a recognized certificate authority such as DigiCert. The preferred format is PKCS#12, with a file extension of .p12 or .pfx. You can also use a Java keytool keystore.

However, a commercial certificate may be inappropriate for evaluation and test environments. There could be cost reasons, or the lack of stable hostnames. This article discusses the alternatives to a commercial certificate.

The three main alternatives are:

  • A server certificate issued by Let's Encrypt
  • A server certificate issued by your own private Certificate Authority (CA)
  • A self-signed certificate

If you are unfamiliar with the concept of server certificates, some introductory material can be found here.

Information about how to install the certificate can be found in section Installing a Server Certificate, below. The FlexNet Embedded documentation also has information about how to configure the local license server for incoming HTTPS.

Server Certificate Issued by Let's Encrypt

The use of Let's Encrypt comes with the following requirements:

  • Let's Encrypt uses an ACME challenge protocol to securely issue certificates. In order to do this, it will temporarily spin up a built-in webserver. You must provide external access to this webserver through any corporate firewall for the duration of the session.
  • You will also need a functioning fully qualified domain name that will work from outside your domain.
  • "localhost" is not supported.
  • IP addresses are not supported, not even as subjectAltName.
  • Port 80 must be available (you may need to temporarily stop Apache, Nginx or IIS for this).

If you cannot meet these requirements, consider the private CA approach described in the next section, Private Certificate Authority.

Start by installing Certbot, following the instructions here for your system. Choose "None of the above" for the Software dropdown list.

You should now be able to generate a certificate by executing this command:

  • On Unix:
sudo certbot certonly –standalone
  • On Windows:
C:\WINDOWS\system32> certbot certonly –standalone

Answer the questions prompted in your browser.

Let's Encrypt certificates are of short duration (90 days). However, the Certbot installation offers the possibility to automatically renew your certificates, as explained on the Certbot website.

Private Certificate Authority

Setting up a private Certificate Authority (CA) used to be a complex operation in OpenSSL scripting. Lots of the complexity can be removed by using a certificate manager, such as certstrap. You can use certstrap directly (which involves building it in Go), or use the Docker image instead.

server-cert is a bash script (Linux, macOS) that automates the process of setting up a CA and using it to create a server certificate. The script will display information on certificate installation, and how to install the CA certificate on Linux, Windows or macOS for use by REST clients or browsers.

#!/bin/bash
#
# Script for creating evaluation/test server certificates, without going down the self-signed route.
# Creates a local certificate authority (CA) to sign server certificates.
#
# Requires:  Docker, OpenSSL.
#
# References:  https://github.com/square/certstrap, https://hub.docker.com/r/squareup/certstrap.
#
# This script will create server certificates in a designated directory (default:  ./certificates).
#
# On first run, the CA will be created. The critical file is the .key one, which should not be
# shared with anyone. The CA files are stored in '-r--------' mode, but feel free to add additional
# security (e.g. an encrypted volume)
#
# Usage:
#   Create a server certificate for host lls.mycompany.com:
#       - server-cert --ca-name mycompany --server lls.mycompany.com
#
#   Create a server certificate for host lls.mycompany.com, and view contents:
#       - server-cert --ca-name mycompany --server lls.mycompany.com --view
#
# These commands will create a file called com.mycompany.lls.p12 in the certificates directory. 
# That's the file that LLS needs. Note that it must be a hostname - 
# this script does not support IP addresses.
#
# Security:
#   Note that the CA password is supplied on the command line for certpath invocations.
#   This is a ease-of-use versus security issue. If concerned, remove this from the
#   certstrap sign call:
#           --passphrase "${CA_PASSWORD}"
#   You will then be prompted to re-enter the CA password.
#
# Notes:   
#   The certificates are minimal, but functional. Optional information (e.g. department info)
#   is not supplied.
 
set -e
 
trap cleanup EXIT
 
function cleanup() {
    setmode 0400
 
    # Remove intermediary files.
    rm -f "${CERT_DIR}/${HOSTNAME}-chain.pem" "${CERT_DIR}/${HOSTNAME}.csr" "${CERT_DIR}/${CA_NAME}.crl"
}
 
function setmode() {
    for ext in crt der key ; do
        if [ -f "${CERT_DIR}/${CA_NAME}.${ext}" ] ; then
            chmod "$1" "${CERT_DIR}/${CA_NAME}.${ext}"
        fi
    done
}
 
function abspath() {
    # shellcheck disable=SC2164
    echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
}
 
function certstrap() {
    docker run -it -v "${CERT_DIR}":/out squareup/certstrap "$@"
}
 
CA_NAME="LocalCA"
CA_PASSWORD=
CERT_DIR=$(abspath ./certificates)
HOSTNAME=localhost
export SERVER_PASSWORD=
VIEW_CERT=false
 
function prompt_ca_password() {
    if [ ! -f "${CERT_DIR}/${CA_NAME}.crt" ] ; then
        echo Make a note of the CA password you create. It will be needed for future certificate creation.
    fi
 
    if [ -z "${CA_PASSWORD}" ] ; then
        read -r -s -p "CA Password: " CA_PASSWORD
        echo
    fi
}
 
function create_ca() {
    # One-time creation of CA certificate.
    echo Generating initial CA certificate
    certstrap init --common-name "${CA_NAME}" --passphrase "${CA_PASSWORD}" --years 10
 
    # And create a DER variant for Win, Mac systems.
    openssl x509 -inform PEM -outform DER -in "${CERT_DIR}/${CA_NAME}.crt" -out "${CERT_DIR}/${CA_NAME}.der"
}
 
function create_server_cert() {
    if [ -z "$HOSTNAME" ] ; then
        echo server hostname is required
        exit 1
    fi
 
    certstrap request-cert --common-name "${HOSTNAME}" --passphrase ""
    certstrap sign "${HOSTNAME}" --CA "${CA_NAME}" --years 3 --passphrase "${CA_PASSWORD}"
 
    # Create PKCS#12 variant of *.(key,crt)
    openssl pkcs12 -export -out "${CERT_DIR}/${HOSTNAME}.p12" -inkey "${CERT_DIR}/${HOSTNAME}.key" \
            -in "${CERT_DIR}/${HOSTNAME}.crt" \
            -certfile "${CERT_DIR}/${CA_NAME}.crt" -passout "pass:"
 
    # Convert that to PEM. Don't bother with passwords - intermediate files are ephemeral.
    openssl pkcs12 -in "${CERT_DIR}/${HOSTNAME}.p12" -out "${CERT_DIR}/${HOSTNAME}.pem" -nodes -passin "pass:"
 
    # Concatenate CA and localhost PEM to generate a chain.
    cat "${CERT_DIR}/${CA_NAME}.crt" "${CERT_DIR}/${HOSTNAME}.pem" >"${CERT_DIR}/${HOSTNAME}-chain.pem"
 
    # Convert the PEM chain to PKCS#12
    echo
    echo Make a note of the server certificate password you create.
    echo You will need to specify it in LLS\'s local-configuration.yaml file, preferably
    echo obfuscated by \"java -jar flexnetls.jar -password \<PASSWORD\>\".
    echo
    read -r -s -p "Server Certificate Password: " SERVER_PASSWORD
 
    openssl pkcs12 -export -inkey "${CERT_DIR}/${HOSTNAME}.key" -in "${CERT_DIR}/${HOSTNAME}-chain.pem" \
            -out "${CERT_DIR}/${HOSTNAME}.p12" -passout "env:SERVER_PASSWORD"
}
 
function ca_install_instructions() {
    cat <<-EOF
        If you have Java applications that need to talk to LLS, you should generally import
        the CA certificate into the JRE cacerts file, or use it directly with the application.
        To import into cacerts:
            keytool -importcert -alias $CA_NAME -keystore $JAVA_HOME/jre/lib/security/cacerts -file $CA_NAME.der
        The default password is "changeit", and you really should.
 
        If you have non-Java entities that need to communicate through HTTPS with LLS, then
        the CA certificate - $CERT_DIR/$CA_NAME.crt - will need to be installed at system level.
 
        Redhat 7
          sudo cp $CERT_DIR/$CA_NAME.crt /etc/pki/ca-trust/source/anchors/$CA_NAME.pem
          sudo update-ca-trust
        Redhat 6
          Ensure that you have the Shared System Certificates feature (update if necessary)
          sudo update-ca-trust enable
          sudo cp $CERT_DIR/$CA_NAME.crt /etc/pki/ca-trust/source/anchors/$CA_NAME.pem
          sudo update-ca-trust
        Ubuntu
          sudo cp $CERT_DIR/$CA_NAME.crt /usr/local/share/ca-certificates
          sudo update-ca-certificates
        Windows 10
          Search for "mmc.exe", right click and select "Run as Administrator".
          Select "File"->"Add Remove Snap-in"
          Select "Certificates" in the available snap-ins and click the "Add" button to add it to the selected snap-ins.
          Select "My user account" on the Certificated snap-in screen.
          Click on "Certificates - Current User" , "Trusted Root Certification Authorities" -> "Certificates"
          Import $CA_NAME.der certificate - Right click "Certificates", "All Tasks" -> "Import",
          browse to the certificate and complete the certificate import.
        Mac OS X
          sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" $CERT_DIR/$CA_NAME.der
 
EOF
}
 
function view_server_cert() {
    openssl pkcs12 -nokeys -info -in "${CERT_DIR}/${HOSTNAME}.p12" -passin "env:SERVER_PASSWORD"
}
 
function help() {
    echo "usage: $0 [--help] [--ca-dir dir] [--ca-name name] [--server hostname] ["
    echo
    echo Default CA name is \'LocalCA\', default server name is \'localhost\'.
}
 
if ! command -v docker &> /dev/null ; then
    echo "docker could not be found, please install"
    exit 1
fi
 
if ! command -v openssl &> /dev/null ; then
    echo "openssl could not be found, please install"
    exit 1
fi
 
if [ "$(uname)" = "Darwin" ] ; then
    # Homebrew keg install of GNU getopt
    GETOPT=$(find /usr/local/Cellar/gnu-getopt/ -regex '.*/bin/getopt' | head -1)
    if [ -z "$GETOPT" ] ; then
        echo GNU getopt was not found. It can be installed with \'brew install getopt\'.
        exit 1
    fi
else
    GETOPT=getopt
fi
 
 
OPTS=$($GETOPT -n "$0" -o h: --long "help,cert-dir:,ca-name:,server:,view"  -- "$@")
 
# shellcheck disable=SC2181
if [ $? -ne 0 ]; then
    exit 1
fi
 
eval set -- "$OPTS"
while true ; do
    case "$1" in
    -h|--help)
        help
        exit 1
        shift;;
    --ca-name)
        CA_NAME="$2"
        shift 2;;
    --cert-dir)
        CERT_DIR=$(abspath "$2")
        shift 2;;
    --server)
        HOSTNAME=$2
        shift 2;;
    --view)
        VIEW_CERT=true
        shift 1;;
    --)
      shift
      break;;
    esac
done
 
mkdir -p "$CERT_DIR"                # Certificates are generated in this directory
 
prompt_ca_password
 
if [ ! -f "./certificates/${CA_NAME}.crt" ] ; then
    create_ca
 
    ca_install_instructions
else
    # Ensure CA files are readable by the Docker container.
    setmode 0444
fi
 
create_server_cert
if $VIEW_CERT ; then
    view_server_cert
fi

Self-signed Certificates

While using self-signed certificates is possible, this is not discussed in this article due to the associated security risks.

Alternatives

You can always handle HTTPS with an Apache or Nginx reverse proxy, forwarding the calls as HTTP to the local license server. This has the following benefits:

  • HTTPS handling is offloaded from the local license server
  • The reverse proxy can be an externally-facing one, and therefore does not have the domain name problems mentioned above.

Installing a Server Certificate

This section describes how to install a server certificate. To install it, you need to edit the file local-configuration.yaml, which contains local settings available to the local license server.

In local-configuration.yaml, edit the https-in block. It originally looks like this:

# HTTPS server mode
https-in: 
# Set to true to enable 
enabled: false 
# HTTPS listening port 
port: 1443 
# Path to keystore 
keystore-path: path-to-your-keystore 
# Keystore password. You can obfuscate this with java -jar flexnetls.jar -password your-password-here 
keystore-password: changeit

Do the following:

  • Set enabled: true, and change the keystore-path and keystore-password entries as required.
  • Ensure that the keystore file (the file with a .p12 extension) is readable by the local license server service. (On Linux, use a command-line such as sudo chown flexnetls <FILE>).
Labels (1)
Was this article helpful? Yes No
No ratings
Version history
Revision #:
3 of 3
Last update:
‎Mar 09, 2021 05:36 AM
Updated by:
 
Contributors