File: signer.go

package info (click to toggle)
golang-github-foxboron-go-tpm-keyfiles 0.0~git20250520.c3c3a4e-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 228 kB
  • sloc: makefile: 9
file content (168 lines) | stat: -rw-r--r-- 4,038 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package keyfile

import (
	"crypto"
	"crypto/rsa"
	"fmt"
	"io"
	"sync"

	"github.com/google/go-tpm/tpm2"
	"github.com/google/go-tpm/tpm2/transport"
)

// Ideally, this would be per-TPM, but e.g. go-tpm-tools just uses a global mutex.
var signerMutex sync.Mutex

// TPMKeySigner implements the crypto.Signer interface for TPMKey
// It allows passing callbacks for TPM, ownerAuth and user auth.
type TPMKeySigner struct {
	key       *TPMKey
	ownerAuth func() ([]byte, error)
	tpm       func() transport.TPMCloser
	auth      func(*TPMKey) ([]byte, error)
}

var _ crypto.Signer = &TPMKeySigner{}

// Returns the crypto.PublicKey
func (t *TPMKeySigner) Public() crypto.PublicKey {
	pk, err := t.key.PublicKey()
	// This shouldn't happen!
	if err != nil {
		panic(fmt.Errorf("failed producing public: %v", err))
	}
	return pk
}

// Sign implementation
func (t *TPMKeySigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
	var digestalg, signalg tpm2.TPMAlgID

	signerMutex.Lock()
	defer signerMutex.Unlock()

	auth := []byte("")
	if t.key.HasAuth() {
		p, err := t.auth(t.key)
		if err != nil {
			return nil, err
		}
		auth = p
	}

	switch opts.HashFunc() {
	case crypto.SHA256:
		digestalg = tpm2.TPMAlgSHA256
	case crypto.SHA384:
		digestalg = tpm2.TPMAlgSHA384
	case crypto.SHA512:
		digestalg = tpm2.TPMAlgSHA512
	default:
		return nil, fmt.Errorf("%s is not a supported hashing algorithm", opts.HashFunc())
	}

	signalg = t.key.KeyAlgo()
	if _, ok := opts.(*rsa.PSSOptions); ok {
		if signalg != tpm2.TPMAlgRSA {
			return nil, fmt.Errorf("Attempting to use PSSOptions with non-RSA (alg %x) key", signalg)
		}
		signalg = tpm2.TPMAlgRSAPSS
	}

	ownerauth, err := t.ownerAuth()
	if err != nil {
		return nil, err
	}

	sess := NewTPMSession(t.tpm())
	sess.SetTPM(t.tpm())

	return SignASN1(sess, t.key, ownerauth, auth, digest, digestalg, signalg)
}

func NewTPMKeySigner(k *TPMKey, ownerAuth func() ([]byte, error), tpm func() transport.TPMCloser, auth func(*TPMKey) ([]byte, error)) *TPMKeySigner {
	return &TPMKeySigner{
		key:       k,
		ownerAuth: ownerAuth,
		tpm:       tpm,
		auth:      auth,
	}
}

// TPMHandleSigner implements the crypto.Signer interface for an already-loaded TPMKey
type TPMHandleSigner struct {
	tpm     transport.TPMCloser
	pubKey  crypto.PublicKey
	keyAlgo tpm2.TPMAlgID
	keySize int
	handle  handle
}

func (t *TPMHandleSigner) Public() crypto.PublicKey {
	return t.pubKey
}

func (t *TPMHandleSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
	var digestalg, signalg tpm2.TPMAlgID
	var digestlength int

	switch opts.HashFunc() {
	case crypto.SHA256:
		digestalg = tpm2.TPMAlgSHA256
		digestlength = 32
	case crypto.SHA384:
		digestalg = tpm2.TPMAlgSHA384
		digestlength = 48
	case crypto.SHA512:
		digestalg = tpm2.TPMAlgSHA512
		digestlength = 64
	default:
		return nil, fmt.Errorf("%s is not a supported hashing algorithm", opts.HashFunc())
	}

	if len(digest) != digestlength {
		return nil, fmt.Errorf("incorrect checksum length. expected %v got %v", digestlength, len(digest))
	}

	signalg = t.keyAlgo
	if _, ok := opts.(*rsa.PSSOptions); ok {
		if signalg != tpm2.TPMAlgRSA {
			return nil, fmt.Errorf("Attempting to use PSSOptions with non-RSA (alg %x) key", signalg)
		}
		signalg = tpm2.TPMAlgRSAPSS
	}

	signerMutex.Lock()
	defer signerMutex.Unlock()

	rsp, err := TPMSign(t.tpm, t.handle, digest, digestalg, t.keySize, signalg)
	if err != nil {
		return nil, err
	}
	return EncodeSignatureASN1(rsp)
}

func NewTPMHandleSigner(
	tpm transport.TPMCloser,
	pubKey crypto.PublicKey,
	keyAlgo tpm2.TPMAlgID,
	keySize int,
	handle handle,
) TPMHandleSigner {
	return TPMHandleSigner{tpm, pubKey, keyAlgo, keySize, handle}
}

func NewTPMHandleSignerFromKey(
	tpm transport.TPMCloser,
	key *TPMKey,
	handle handle,
) TPMHandleSigner {
	pk, err := key.PublicKey()
	// This shouldn't happen!
	if err != nil {
		panic(fmt.Errorf("failed producing public: %v", err))
	}

	return TPMHandleSigner{tpm, pk, key.KeyAlgo(), key.KeySize(), handle}
}