tpm2: add a `crypto.Signer` for keys held in a TPM
- 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
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