google / google/go-tpm

tpm2: add a `crypto.Signer` for keys held in a TPM

Open
#443 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
673
Forks
188
PR merge metrics
No merged PRs in 30d

Description

The TPMDirect API has no `crypto.Signer`. Neither does `legacy/tpm2`: the only first-party signer lives in go-tpm-tools([`client.GetSigner`](https://github.com/google/go-tpm-tools/blob/master/client/signer.go)), on the legacy API. So a key in a TPM cannot be used with `crypto/tls`, `x509.CreateCertificateRequest`, or anything else that takes a `crypto.Signer`, without either the legacy stack or a third-party library.

`crypto.Signer` is what makes a TPM key useful outside TPM-specific code: `crypto/tls` accepts any `crypto.Signer` as a private key.

This gap is being filled repeatedly downstream:
- [go-tpm-tools `client.GetSigner`](https://github.com/google/go-tpm-tools/blob/master/client/signer.go) (legacy API)
- [foxboron/go-tpm-keyfiles](https://github.com/foxboron/go-tpm-keyfiles) (TPMKeySigner, TPMHandleSigner, TPMDirect)
- [salrashid123/tpmsigner](https://github.com/salrashid123/tpmsigner) (TPMDirect)
- [bschaatsbergen/go-tpm-tls](https://github.com/bschaatsbergen/go-tpm-tls) (mine, legacy via go-tpm-tools)

And there is migration pressure toward TPMDirect: [spiffe/spire#4305](https://github.com/spiffe/spire/issues/4305) wants the SPIRE TPM attestor off the legacy API.

## Proposal

A `crypto.Signer` over a loaded key, somewhere in the `tpm2` module:

```go
// NewSigner returns a crypto.Signer backed by the key at handle. Signing
// happens inside the TPM: the digest goes in, a signature comes back, and
// the private key never leaves it.
func NewSigner(t transport.TPM, handle tpm2.TPMHandle, auth tpm2.Session) (crypto.Signer, error)
```

Which is enough to put a TPM key straight into a `tls.Config`:

```go
tpm, err := transport.OpenTPM()
// ...
defer tpm.Close()

signer, err := tpm2.NewSigner(tpm, 0x81000004, tpm2.PasswordAuth(nil))
// ...

cfg := &tls.Config{
Certificates: []tls.Certificate{{
Certificate: [][]byte{certDER},
PrivateKey: signer,
}},
}
```

I understand helpers have historically been left to go-tpm-tools, but go-tpm-tools never adopted TPMDirect, so direct-API users have no first-party path today.

Contributor guide

Open the contributing guide

Research direction

Start by reading the TPMDirect API and the referenced go-tpm-tools client.GetSigner implementation to understand the existing signing interfaces. Define the signer around a loaded TPM key and verify that it satisfies crypto.Signer for crypto/tls and x509.CreateCertificateRequest while keeping the private key in the TPM.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cryptography, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.