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}
}
|