As described in the introduction, using a hardware security model to hold potentially-sensitive provisioning key material may be a good idea. In this document, we first describe how to use QEMU to simulate using an HSM and give outlines of how to generate the requisite keys and certificates. How exactly it’s done for your particular HSM will, of course, vary significantly, and will likely require some BSP integration work so that aktualizr knows how to access the keys from the HSM during provisioning.

The following steps should work when building for a QEMU target:

  1. Generate a root CA private key and self-signed certificate.

    If you do not have your own CA certificate for signing device certificates, you can generate a self-signed certificate for testing.

    First, create a directory structure for the keys, and grab sample configurations for the certificates from the OTA Community Edition project:

    export SERVER_NAME=myservername
    export SERVER_DIR="./${SERVER_NAME}" DEVICES_DIR="./${SERVER_NAME}/devices" CWD="${PWD}"
    mkdir -p "$DEVICES_DIR" certs
    for file in client.cnf device_ca.cnf server.ext client.ext server.cnf server_ca.cnf; do
      curl -o certs/$file$file

    Then, generate the key and cert using openssl on the command line:

      openssl ecparam -genkey -name prime256v1 | openssl ec -out "${SERVER_DIR}/ca.key"
      openssl req -new -x509 -days 3650 -config "${CWD}/certs/server_ca.cnf" -key "${SERVER_DIR}/ca.key" \
        -out "${SERVER_DIR}/server_ca.pem"
      openssl ecparam -genkey -name prime256v1 | openssl ec -out "${SERVER_DIR}/server.key"
      openssl req -new -config "${CWD}/certs/server.cnf" -key "${SERVER_DIR}/server.key" -out "${SERVER_DIR}/server.csr"
      openssl x509 -req -days 3650 -extfile "${CWD}/certs/server.ext" -in "${SERVER_DIR}/server.csr" -CAcreateserial \
        -CAkey "${SERVER_DIR}/ca.key" -CA "${SERVER_DIR}/server_ca.pem" -out "${SERVER_DIR}/server.crt"
      cat "${SERVER_DIR}/server.crt" "${SERVER_DIR}/server_ca.pem" > "${SERVER_DIR}/server.chain.pem"
      openssl ecparam -genkey -name prime256v1 | openssl ec -out "${DEVICES_DIR}/ca.key"
      openssl req -new -x509 -days 3650 -key "${DEVICES_DIR}/ca.key" -config "${CWD}/certs/device_ca.cnf" \
        -out "${DEVICES_DIR}/ca.crt"

    This will create a ./${SERVER_DIR}/devices/ directory with the ca.crt certificate and a ca.key private key. Keep the private key safe and secure.

  2. Upload the root CA certificate to the server. To add a root CA certificate to ATS Garage, contact

  3. Generate a device certificate and key, and sign it with the root CA you just created.

    Generate a UUID for the device, and make a directory for it:

    export DEVICE_UUID=$(uuidgen | tr "[:upper:]" "[:lower:]")
    export device_id=${DEVICE_ID:-${DEVICE_UUID}} device_dir="${DEVICES_DIR}/${DEVICE_UUID}"
    mkdir -p "${device_dir}"

    Then, generate the device certificate and key using openssl:

      openssl ecparam -genkey -name prime256v1 | openssl ec -out "${device_dir}/"
      openssl pkcs8 -topk8 -nocrypt -in "${device_dir}/" -out "${device_dir}/pkey.pem"
      openssl req -new -config "${CWD}/certs/client.cnf" -key "${device_dir}/pkey.pem" -out "${device_dir}/${device_id}.csr"
      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"
      cat "${device_dir}/client.pem" "${DEVICES_DIR}/ca.crt" > "${device_dir}/${device_id}.chain.pem"
      ln -s "${SERVER_DIR}/server_ca.pem" "${device_dir}/ca.pem" || true
      openssl x509 -in "${device_dir}/client.pem" -text -noout
  4. Add the internal root CA certificate of the device gateway the device will connect to. To get the device gateway’s certificate, use openssl:

    export device_gateway=your-gateway-url # for ATS Garage, looks something like
    openssl s_client -connect ${device_gateway}:8000 -servername $device_gateway -showcerts | \
      sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ${device_dir}/root.crt
  5. Add the following lines to your conf/local.conf:

    SOTA_CLIENT_PROV = "aktualizr-hsm-prov"
  6. Build a standard image using bitbake. Make sure an ssh server is installed; usually you can do this with IMAGE_INSTALL_append = " dropbear ".

  7. Boot the image.

  8. Copy the device credentials and device gateway root CA certificate to the device’s HSM. For the QEMU simulated HSM, enter the device directory whose credentials you wish to copy, then do:

    scp -P 2222 -pr ./ root@localhost:/var/sota/token
  9. The server authenticates the client device by verifying that the client’s certificate was signed by the root CA private key that was uploaded in step 2.

  10. The client device authenticates the server by verifying that the server’s certificate was signed by the server’s internal root CA private key.

  11. The device is provisioned, and will appear online in the web UI.

More information is available on how auto-provisioning, implicit provisioning (with or without an HSM), and the various files included in are related.