Files
netbird/client/internal/tpm/signer.go
T
2026-09-16 23:00:44 +02:00

62 lines
1.7 KiB
Go

package tpm
import (
"crypto"
"errors"
"fmt"
"io"
"go.step.sm/crypto/tpm/tss2"
)
// KeyPEMType is the PEM block type of a TPM 2.0 key file as defined by
// draft-bottomley-tpm2-keys and written by tpm2-openssl and tpm2-tss-engine.
const KeyPEMType = "TSS2 PRIVATE KEY"
var ErrKeyNeedsAuth = errors.New("TPM key requires an authorization value")
// ParseKey reads a TSS2 key file and returns a signer that produces every signature
// inside the TPM; only the digest goes in and only the signature comes out. A key with
// a persistent parent is loaded under it, a key whose parent is a hierarchy under the
// TCG default ECC primary that tpm2-openssl and tpm2-tss-engine derive as well. Keys
// guarded by an authorization value are rejected, since nothing can supply it without
// prompting.
func ParseKey(der []byte) (crypto.Signer, error) {
key, err := tss2.ParsePrivateKey(der)
if err != nil {
return nil, fmt.Errorf("parse TSS2 key: %w", err)
}
if !key.EmptyAuth {
return nil, ErrKeyNeedsAuth
}
public, err := key.Public()
if err != nil {
return nil, fmt.Errorf("decode TSS2 public key: %w", err)
}
return &keySigner{key: key, public: public}, nil
}
type keySigner struct {
key *tss2.TPMKey
public crypto.PublicKey
}
func (s *keySigner) Public() crypto.PublicKey {
return s.public
}
func (s *keySigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
rwc, err := Open()
if err != nil {
return nil, err
}
defer func() { _ = rwc.Close() }()
signer, err := tss2.CreateSigner(rwc, s.key)
if err != nil {
return nil, fmt.Errorf("load TSS2 key: %w", err)
}
signer.SetSRKTemplate(tss2.ECCSRKTemplate)
return signer.Sign(rand, digest, opts)
}