Skip to content

Commit

Permalink
Add signing support for keys generated on Windows
Browse files Browse the repository at this point in the history
When generating a new key using a Windows TPM, a `wrappedKey20` was
returned, which couldn't be used for signing on Windows, as it's
backed by a `windowsTPM`. The `wrappedKey20` seems to be a type
specifically aimed at usage with a `wrappedTPM20`, which in turn
seems to be used on Linux and for testing, but not when instantiating
a TPM on Windows.

This commit adds the `newWindowsKey20` function, which returns
a key backed by a `windowsTPM`. The key is a `windowsAK20`,
now also conforming to the `key` interface, so that it can be used
for signing purposes.
  • Loading branch information
hslatman authored and mjg59 committed May 24, 2023
1 parent 181d803 commit 6f99d74
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 2 deletions.
60 changes: 60 additions & 0 deletions attest/key_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
package attest

import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"errors"
"fmt"

tpm1 "github.com/google/go-tpm/tpm"
Expand Down Expand Up @@ -217,3 +221,59 @@ func (k *windowsAK20) certify(tb tpmBase, handle interface{}) (*CertificationPar
}
return certify(tpm, hnd, akHnd, scheme)
}

// newWindowsKey20 returns a pointer to a windowsAK20, conforming to the key interface. This
// allows the resulting windowsAK20 to be used as a signing key.
func newWindowsKey20(hnd uintptr, pcpKeyName string, public, createData, createAttest, createSig []byte) key {
return &windowsAK20{
hnd: hnd,
pcpKeyName: pcpKeyName,
public: public,
createData: createData,
createAttestation: createAttest,
createSignature: createSig,
}
}

func (k *windowsAK20) blobs() ([]byte, []byte, error) {
return nil, nil, errors.New("not implemented")
}

func (k *windowsAK20) certificationParameters() CertificationParameters {
return CertificationParameters{
Public: k.public,
CreateAttestation: k.createAttestation,
CreateSignature: k.createSignature,
}
}

func (k *windowsAK20) decrypt(tpmBase, []byte) ([]byte, error) {
return nil, errors.New("not implemented")
}

func (k *windowsAK20) sign(tb tpmBase, digest []byte, pub crypto.PublicKey, opts crypto.SignerOpts) ([]byte, error) {

t, ok := tb.(*windowsTPM)
if !ok {
return nil, fmt.Errorf("expected *windowsTPM, got %T", tb)
}

rw, err := t.pcp.TPMCommandInterface()
if err != nil {
return nil, fmt.Errorf("error getting TPM command interface: %w", err)
}

hnd, err := t.pcp.TPMKeyHandle(k.hnd)
if err != nil {
return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err)
}

switch pub.(type) {
case *ecdsa.PublicKey:
return signECDSA(rw, hnd, digest)
case *rsa.PublicKey:
return signRSA(rw, hnd, digest, opts)
}

return nil, fmt.Errorf("unsupported signing key type: %T", pub)
}
9 changes: 7 additions & 2 deletions attest/tpm_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (

tpm1 "github.com/google/go-tpm/tpm"
"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpmutil"
tpmtbs "github.com/google/go-tpm/tpmutil/tbs"
"golang.org/x/sys/windows"
)
Expand Down Expand Up @@ -366,7 +365,13 @@ func (t *windowsTPM) newKey(ak *AK, config *KeyConfig) (*Key, error) {
return nil, fmt.Errorf("access public key: %v", err)
}

return &Key{key: newWrappedKey20(tpmutil.Handle(hnd), blob, pub, nil, cp.CreateAttestation, cp.CreateSignature), pub: pubKey, tpm: t}, nil
// TODO(hslatman): do we need the blob?
_ = blob

// Return a new windowsAK20 certified by the ak, conforming to the key interface. This allows the
// key to be verified to have been generated by the same TPM as the ak was generated with. The
// resulting key can be used for signing purposes.
return &Key{key: newWindowsKey20(hnd, name, pub, cp.CreateData, cp.CreateAttestation, cp.CreateSignature), pub: pubKey, tpm: t}, nil
}

func (t *windowsTPM) loadKey(opaqueBlob []byte) (*Key, error) {
Expand Down

0 comments on commit 6f99d74

Please sign in to comment.