devtpm — /dev/tpmrm0 transport
github.com/go-tpm2/devtpm is a pure-Go TPM 2.0 transport over the Linux
kernel TPM character device (/dev/tpmrm0). It implements
common.Transport over a Linux TPM char device and is the
node-side host-TPM transport for weft remote attestation: on a real Linux
node it gives the attest Node side a channel to the host's
hardware (or firmware / vTPM) TPM, where the tis/crb
MMIO interfaces are not available. v0.1.0.
go get github.com/go-tpm2/devtpm
Device model
The Linux tpm subsystem (drivers/char/tpm) exposes a TPM through two
character devices, both with the same framing:
| Device | Role |
|---|---|
/dev/tpmrm0 |
Resource-manager channel (DefaultDevice). Each open fd is an independent, multiplexed command channel; the kernel RM virtualizes the TPM's scarce transient-object/session slots and flushes a client's context on close. Prefer this. |
/dev/tpm0 |
Raw channel. Single-open, unmediated, no handle virtualization — a leaked transient handle can wedge the whole TPM. |
The framing this package relies on: one write() delivers exactly one complete
command, and the matching read() returns exactly one complete response. Send
therefore does one Write of the full command and one Read of the full
response — no length prefix, no chunking.
Because that contract is just "raw TPM2 bytes, one command per write, one
response per read", New also accepts any io.ReadWriteCloser that honors it —
most usefully a unix socket to swtpm's --server data channel, which speaks
the identical raw TPM2 protocol. The validate harness uses
exactly that to drive this transport against a real swtpm on a host with no
/dev/tpmrm0.
Usage
import (
"github.com/go-tpm2/attest"
"github.com/go-tpm2/devtpm"
"github.com/go-tpm2/tpm2"
)
// Open the host's resource-manager TPM channel.
dev, err := devtpm.Open(devtpm.DefaultDevice) // "/dev/tpmrm0"
if err != nil {
// device missing, or insufficient privilege (root / tss group)
}
defer dev.Close()
// *devtpm.Transport satisfies common.Transport, so it plugs straight into the
// go-tpm2/tpm2 command layer and the attestation Node:
tpm := tpm2.New(dev)
node, err := attest.NewNode(tpm, pcrSel)
// node.Quote(nonce) … etc.
Conventions
Pure Go, CGO_ENABLED=0, big-endian TPM wire (via common), GOWORK=off,
BSD-3-Clause on every file, 100% statement coverage.