Skip to content

Use a Trusted Platform Module (TPM) with Elixir and Nerves

License

Notifications You must be signed in to change notification settings

redwirelabs/tpm

Repository files navigation

TPM

Use a Trusted Platform Module (TPM) with Elixir and Nerves.

A TPM can be used to secure the cryptographic keys used for things like SSL/TLS connections and disk encryption.

This library is mainly a wrapper around existing TPM libraries, which are linked in the module docs of this repo. Documentation on how a TPM works can be found there.

Installation

This package can be installed by adding tpm to your list of dependencies in mix.exs:

def deps do
  [
    {:tpm, "~> 0.1.0"}
  ]
end

Add the following to nerves_defconfig:

BR2_PACKAGE_TPM2_TOOLS=y
BR2_PACKAGE_TPM2_TOOLS_FAPI=y
BR2_PACKAGE_TPM2_TSS_ENGINE=y

Usage

Generate a private key. Unlike a traditional private key file, this one requires the TPM to function.

:ok = TPM.TSS.genkey("/data/.ssh/key")

A copy of the key can be stored in the TPM's non-volatile memory as a backup. For example, if the device were factory reset and the disk wiped, the key could be retrieved from the TPM's NV memory and its prior identity would be retained.

{:ok, address} = TPM.nvdefine(size: 1024)
:ok = TPM.nvwrite(address, "/data/.ssh/key")

The private key can be used within the BEAM VM by getting an engine_key_ref.

{:ok, privkey} = TPM.Crypto.privkey("/data/.ssh/key")

Creating a certificate signing request

Some connections require the client to provide a signed certificate, or else the connection will be rejected.

Generate a public key from the private key reference.

public_key_pem =
  privkey
  |> TPM.Crypto.pubkey
  |> X509.PublicKey.to_pem

File.write!("/data/.ssh/key.pub", public_key_pem)

Create the certificate signing request.

csr_pem =
  privkey
  |> TPM.Crypto.csr("Device ID", "My Organization")
  |> X509.CSR.to_pem

File.write!("/data/.ssh/csr.pem", csr_pem)

Copy the CSR from the device with cat on the device or scp on the host and sign the CSR with the root or intermediate CA. Copy the signed certificate back to the device. For some connections, concatenating the entire certificate bundle into a file may be necessary.

Setting the TCTI

By default, the TPM Command Transmission Interface (TCTI) is set to device:/dev/tpmrm0 since this is the default path for a hardware TPM. This can be changed by setting the :tcti application property in the project's mix config.

config :tpm, :tcti, "device:/dev/tpmrm0"