OTA Connect Developer Guide

Generate a device certificate using an HSM

This section will demonstrate an example of handling device certificates with HSM and was tested using a NitroKey HSM and OpenSC. Instructions will vary depending on your target hardware.

The steps are very similar to those described in Device Certificate Generation with the main difference being that the device keys are generated on the the HSM. Please make sure that you understood and tested these steps before continuing here.

Preparing the HSM

You can directly follow the steps provided by NitroKey for this section.

At the end, you should have an empty HSM. The SO-PIN should be kept in a safe place and won’t be needed for the rest of this guide. We will however assume that you kept the PIN in a shell variable in the next instructions:


Generating the certificate and Uptane keys

To continue, you will have to set up a root certificate, as described in Generate a self-signed root certificate. If you chose to use an external CA, you will need to send them the certificate signing request (csr file) and obtain the certificate, instead of generating it yourself.

  1. Install necessary dependencies

    sudo apt install opensc-pkcs11 openssl
  2. Generate an ID for the device, and make a directory for it. This ID should be unique within your fleet, so we recommend using a UUID if you do not already have a scheme of unique identifiers.

    export device_id=$(uuidgen | tr "[:upper:]" "[:lower:]")
    export device_dir=${fleetname}/devices/${device_id}
    mkdir -p ${device_dir}
  3. Generate a key on the device with id 02

    pkcs11-tool -l --pin $PIN --keypairgen --key-type EC:prime256v1 --id 02 --label devicekey
  4. Create a configuration file for OpenSSL, named hsm.conf:

    # PKCS11 engine config
    openssl_conf = openssl_def
    engines = engine_section
    distinguished_name = req_distinguished_name
    # empty.
    pkcs11 = pkcs11_section
    engine_id = pkcs11
    dynamic_path = /usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so
    MODULE_PATH = /usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so
    PIN = $PIN
    init = 0

    dynamic_path, MODULE_PATH and PIN will need to be changed depending on your system installation and HSM pin.

  5. Generate a Certificate Signing Request using the key:

    OPENSSL_CONF=./hsm.conf openssl req -new -config "$CWD/certs/client.cnf" -engine pkcs11 -keyform engine -key 4:02 -out "$device_dir/$device_id.csr"

    The 4:02 indicates the slot:id to use for the key, you will probably have to change it depending on your setup. In particular, the slot can be found by running pkcs11-tool -L:

    Available slots:
    Slot 1 (0x4): Nitrokey Nitrokey HSM (010000000000000000000000) 01 00
      token label        : UserPIN (test)
      token manufacturer : www.CardContact.de
      token model        : PKCS#15 emulated
      token flags        : login required, rng, token initialized, PIN initialized
      hardware version   : 24.13
      firmware version   : 2.6
      serial num         : DENK0200509
      pin min/max        : 6/15

    The slot number is the one in hexadecimal between parentheses.

  6. Generate the device certificate and store it in the HSM:

    openssl x509 -req -days 365 -extfile "${CWD}/certs/client.ext" -in "${device_dir}/${device_id}.csr" \
        -CAkey "${DEVICES_DIR}/ca.key" -CA "${DEVICES_DIR}/ca.crt" -CAcreateserial -out "${device_dir}/client.pem"
  7. Save the certificate on the HSM:

    openssl x509 -in "$device_dir/client.pem" -out "$device_dir/client.der" -outform der
    pkcs11-tool -l --pin $PIN --write-object "$device_dir/client.der" --type cert --id 01 --label devicecert
  8. Generate an RSA key to sign Uptane metadata

    pkcs11-tool -l --pin $PIN --keypairgen --key-type RSA:2048 --id 03 --label uptanekey

    At this point, you can verify that your device contains the three objects by running pkcs11-tool -O:

    Using slot 1 with a present token (0x4)
    Public Key Object; RSA 2048 bits
      label:      uptanekey
      ID:         03
      Usage:      encrypt, verify, wrap
    Public Key Object; EC  EC_POINT 256 bits
      EC_POINT:   044104d59c51e5454d46787bdb9db3ea450bc118f71bf5fd352cf0ae4e41720d897eb4051345d0ef5470fd4e3b1c3c18066199915c88eeab7a3ad3e595d4ecaa38f564
      EC_PARAMS:  06082a8648ce3d030107
      label:      devicepriv
      ID:         02
      Usage:      verify
    Certificate Object; type = X.509 cert
      label:      Certificate
      subject:    DN: CN=089f19e2-2f52-4a30-98f1-66e35cc11611
      ID:         01
    Public Key Object; EC  EC_POINT 256 bits
      EC_POINT:   044104d59c51e5454d46787bdb9db3ea450bc118f71bf5fd352cf0ae4e41720d897eb4051345d0ef5470fd4e3b1c3c18066199915c88eeab7a3ad3e595d4ecaa38f564
      EC_PARAMS:  06082a8648ce3d030107
      label:      Certificate
      ID:         01
      Usage:      encrypt, verify

Setting up aktualizr

The following conditions should be fulfilled:

  • the HSM token should be accessible on the device

  • aktualizr must be compiled with P11 support (refer to Enable device-credential provisioning and install device certificates)

  • supporting libraries, such as OpenSC must be present on the device

  • the device gateway url and TLS root certificate must be obtained from a set of credentials:

    unzip credentials.zip autoprov.url autoprov_credentials.p12
    mv autoprov.url gateway.url
    openssl pkcs12 -in autoprov_credentials.p12 -nokeys -cacerts -out ca.crt
  • aktualizr must be configured to use the gateway url, root certificate and HSM. For example:

    server_url_path = "/var/sota/import/gateway.url"
    cert_source = "pkcs11"
    pkey_source = "pkcs11"
    module = "/usr/lib/opensc-pkcs11.so"
    pass = "1234"
    uptane_key_id = "03"
    tls_clientcert_id = "01"
    tls_pkey_id = "02"
    key_source = "pkcs11"
    base_path = "/var/sota/import"
    tls_cacert_path = "root.crt"

    Note: on Ubuntu Bionic, the OpenSC pkcs11 module lies in /usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so.

Provisioning the device

If all these steps have been followed, the device will establish a TLS connection to the backend using the HSM and will sign its manifests with the Uptane private key.

Yocto integration

You can here refer to the instructions in Enable device-credential provisioning and install device certificates but use OpenSC instead of SoftHSM:

IMAGE_INSTALL_append = " opensc"
SOTA_CLIENT_PROV = "aktualizr-device-prov-hsm"

Also, the configuration fragment /usr/lib/sota/conf.d/20-sota-device-cred-hsm.toml will also have to be modified, as detailed in the previous section, for example with a .bbappend.

Note that for the moment, the gateway url and root certificate will still need to be copied manually to the device.