README.md

# TPM

Use a Trusted Platform Module (TPM) with Elixir and [Nerves](https://nerves-project.org/).

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`:

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

Add the following to `nerves_defconfig`:

```kconfig
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.

```ex
: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.

```ex
{: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](https://www.erlang.org/docs/22/man/crypto#type-engine_key_ref).

```ex
{: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.

```ex
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.

```ex
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.

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