Skip to content

Commit

Permalink
Merge branch 'google:master' into ekcertificates
Browse files Browse the repository at this point in the history
  • Loading branch information
zhsh authored Jun 23, 2023
2 parents 918de01 + d29df30 commit d292432
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 44 deletions.
19 changes: 15 additions & 4 deletions attest/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/google/go-tpm/legacy/tpm2"
"github.com/google/go-tpm/tpm"
"github.com/google/go-tpm/tpmutil"
)

// TPMVersion is used to configure a preference in
Expand Down Expand Up @@ -101,7 +102,7 @@ const (
type ak interface {
close(tpmBase) error
marshal() ([]byte, error)
activateCredential(tpm tpmBase, in EncryptedCredential) ([]byte, error)
activateCredential(tpm tpmBase, in EncryptedCredential, ek *EK) ([]byte, error)
quote(t tpmBase, nonce []byte, alg HashAlg) (*Quote, error)
attestationParameters() AttestationParameters
certify(tb tpmBase, handle interface{}) (*CertificationParameters, error)
Expand All @@ -110,6 +111,10 @@ type ak interface {
// AK represents a key which can be used for attestation.
type AK struct {
ak ak

// The EK that will be used for attestation.
// If nil, an RSA EK with handle 0x81010001 will be used.
ek *EK
}

// Close unloads the AK from the system.
Expand All @@ -130,7 +135,7 @@ func (k *AK) Marshal() ([]byte, error) {
//
// This operation is synonymous with TPM2_ActivateCredential.
func (k *AK) ActivateCredential(tpm *TPM, in EncryptedCredential) (secret []byte, err error) {
return k.ak.activateCredential(tpm.tpm, in)
return k.ak.activateCredential(tpm.tpm, in, k.ek)
}

// Quote returns a quote over the platform state, signed by the AK.
Expand All @@ -155,9 +160,12 @@ func (k *AK) Certify(tpm *TPM, handle interface{}) (*CertificationParameters, er
return k.ak.certify(tpm.tpm, handle)
}

// AKConfig encapsulates parameters for minting keys. This type is defined
// now (despite being empty) for future interface compatibility.
// AKConfig encapsulates parameters for minting keys.
type AKConfig struct {
// The EK that will be used for attestation.
// If nil, an RSA EK with handle 0x81010001 will be used.
// If not nil, it must be one of EKs returned from TPM.EKs().
EK *EK
}

// EncryptedCredential represents encrypted parameters which must be activated
Expand Down Expand Up @@ -205,6 +213,9 @@ type EK struct {
// Public key. Clients or servers can perform an HTTP GET to this URL, and
// use ParseEKCertificate on the response body.
CertificateURL string

// The EK persistent handle.
handle tpmutil.Handle
}

// AttestationParameters describes information about a key which is necessary
Expand Down
77 changes: 61 additions & 16 deletions attest/attest_simulated_tpm20_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,25 +98,37 @@ func TestSimTPM20AKCreateAndLoad(t *testing.T) {
}

func TestSimTPM20ActivateCredential(t *testing.T) {
testActivateCredential(t, false)
}

func TestSimTPM20ActivateCredentialWithEK(t *testing.T) {
testActivateCredential(t, true)
}

func testActivateCredential(t *testing.T, useEK bool) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()

ak, err := tpm.NewAK(nil)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
defer ak.Close(tpm)

EKs, err := tpm.EKs()
if err != nil {
t.Fatalf("EKs() failed: %v", err)
}
ek := chooseEK(t, EKs)

var akConfig *AKConfig
if useEK {
akConfig = &AKConfig{EK: &ek}
}
ak, err := tpm.NewAK(akConfig)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
defer ak.Close(tpm)

ap := ActivationParameters{
TPMVersion: TPMVersion20,
AK: ak.AttestationParameters(),
EK: ek,
EK: ek.Public,
}
secret, challenge, err := ap.Generate()
if err != nil {
Expand Down Expand Up @@ -246,24 +258,57 @@ func TestSimTPM20PCRs(t *testing.T) {
}
}

func TestSimTPM20Persistence(t *testing.T) {
func TestSimTPM20PersistenceSRK(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()

ekHnd, _, err := tpm.tpm.(*wrappedTPM20).getPrimaryKeyHandle(commonRSAEkEquivalentHandle)
srkHnd, _, err := tpm.tpm.(*wrappedTPM20).getStorageRootKeyHandle(commonSrkEquivalentHandle)
if err != nil {
t.Fatalf("getStorageRootKeyHandle() failed: %v", err)
}
if srkHnd != commonSrkEquivalentHandle {
t.Fatalf("bad SRK-equivalent handle: got 0x%x, wanted 0x%x", srkHnd, commonSrkEquivalentHandle)
}

srkHnd, p, err := tpm.tpm.(*wrappedTPM20).getStorageRootKeyHandle(commonSrkEquivalentHandle)
if err != nil {
t.Fatalf("second getStorageRootKeyHandle() failed: %v", err)
}
if srkHnd != commonSrkEquivalentHandle {
t.Fatalf("bad SRK-equivalent handle: got 0x%x, wanted 0x%x", srkHnd, commonSrkEquivalentHandle)
}
if p {
t.Fatalf("generated a new key the second time; that shouldn't happen")
}
}

func TestSimTPM20PersistenceEK(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()

eks, err := tpm.EKs()
if err != nil {
t.Errorf("EKs() failed: %v", err)
}
if len(eks) == 0 || (eks[0].Public == nil) {
t.Errorf("EKs() = %v, want at least 1 EK with populated fields", eks)
}

ek := eks[0]
ekHnd, _, err := tpm.tpm.(*wrappedTPM20).getEndorsementKeyHandle(&ek)
if err != nil {
t.Fatalf("getPrimaryKeyHandle() failed: %v", err)
t.Fatalf("getStorageRootKeyHandle() failed: %v", err)
}
if ekHnd != commonRSAEkEquivalentHandle {
t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, commonRSAEkEquivalentHandle)
if ekHnd != ek.handle {
t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, ek.handle)
}

ekHnd, p, err := tpm.tpm.(*wrappedTPM20).getPrimaryKeyHandle(commonRSAEkEquivalentHandle)
ekHnd, p, err := tpm.tpm.(*wrappedTPM20).getEndorsementKeyHandle(&ek)
if err != nil {
t.Fatalf("second getPrimaryKeyHandle() failed: %v", err)
t.Fatalf("second getEndorsementKeyHandle() failed: %v", err)
}
if ekHnd != commonRSAEkEquivalentHandle {
t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, commonRSAEkEquivalentHandle)
if ekHnd != ek.handle {
t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, ek.handle)
}
if p {
t.Fatalf("generated a new key the second time; that shouldn't happen")
Expand Down
9 changes: 4 additions & 5 deletions attest/attest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package attest

import (
"bytes"
"crypto"
"flag"
"fmt"
"reflect"
Expand Down Expand Up @@ -119,16 +118,16 @@ func TestAKCreateAndLoad(t *testing.T) {
}
}

// chooseEK selects the EK public which will be activated against.
func chooseEK(t *testing.T, eks []EK) crypto.PublicKey {
// chooseEK selects the EK which will be activated against.
func chooseEK(t *testing.T, eks []EK) EK {
t.Helper()

for _, ek := range eks {
return ek.Public
return ek
}

t.Fatalf("No suitable EK found")
return nil
return EK{}
}

func TestPCRs(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion attest/attest_tpm12_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func TestTPMActivateCredential(t *testing.T) {
ap := ActivationParameters{
TPMVersion: TPMVersion12,
AK: ak.AttestationParameters(),
EK: ek,
EK: ek.Public,
}
secret, challenge, err := ap.Generate()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion attest/key_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (k *trousersKey12) close(tpm tpmBase) error {
return nil // No state for tpm 1.2.
}

func (k *trousersKey12) activateCredential(tb tpmBase, in EncryptedCredential) ([]byte, error) {
func (k *trousersKey12) activateCredential(tb tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) {
t, ok := tb.(*trousersTPM)
if !ok {
return nil, fmt.Errorf("expected *linuxTPM, got %T", tb)
Expand Down
4 changes: 2 additions & 2 deletions attest/key_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (k *windowsKey12) marshal() ([]byte, error) {
return out.Serialize()
}

func (k *windowsKey12) activateCredential(t tpmBase, in EncryptedCredential) ([]byte, error) {
func (k *windowsKey12) activateCredential(t tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) {
tpm, ok := t.(*windowsTPM)
if !ok {
return nil, fmt.Errorf("expected *windowsTPM, got %T", t)
Expand Down Expand Up @@ -152,7 +152,7 @@ func (k *windowsKey20) marshal() ([]byte, error) {
return out.Serialize()
}

func (k *windowsKey20) activateCredential(t tpmBase, in EncryptedCredential) ([]byte, error) {
func (k *windowsKey20) activateCredential(t tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) {
tpm, ok := t.(*windowsTPM)
if !ok {
return nil, fmt.Errorf("expected *windowsTPM, got %T", t)
Expand Down
71 changes: 56 additions & 15 deletions attest/wrapped_tpm20.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,58 @@ func (t *wrappedTPM20) info() (*TPMInfo, error) {
return &tInfo, nil
}

// Return value: handle, whether we generated a new one, error.
func (t *wrappedTPM20) getEndorsementKeyHandle(ek *EK) (tpmutil.Handle, bool, error) {
var ekHandle tpmutil.Handle
var ekTemplate tpm2.Public

if ek == nil {
// The default is RSA for backward compatibility.
ekHandle = commonRSAEkEquivalentHandle
ekTemplate = t.rsaEkTemplate()
} else {
ekHandle = ek.handle
switch pub := ek.Public.(type) {
case *rsa.PublicKey:
ekTemplate = t.rsaEkTemplate()
case *ecdsa.PublicKey:
return 0, false, errors.New("ECC EKs are not supported")
default:
return 0, false, fmt.Errorf("unsupported public key type %T", pub)
}
}

_, _, _, err := tpm2.ReadPublic(t.rwc, ekHandle)
if err == nil {
// Found the persistent handle, assume it's the key we want.
return ekHandle, false, nil
}
rerr := err // Preserve this failure for later logging, if needed

keyHnd, _, err := tpm2.CreatePrimary(t.rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", ekTemplate)
if err != nil {
return 0, false, fmt.Errorf("ReadPublic failed (%v), and then CreatePrimary failed: %v", rerr, err)
}
defer tpm2.FlushContext(t.rwc, keyHnd)

err = tpm2.EvictControl(t.rwc, "", tpm2.HandleOwner, keyHnd, ekHandle)
if err != nil {
return 0, false, fmt.Errorf("EvictControl failed: %v", err)
}

return ekHandle, true, nil
}

// Return value: handle, whether we generated a new one, error
func (t *wrappedTPM20) getPrimaryKeyHandle(pHnd tpmutil.Handle) (tpmutil.Handle, bool, error) {
func (t *wrappedTPM20) getStorageRootKeyHandle(pHnd tpmutil.Handle) (tpmutil.Handle, bool, error) {
_, _, _, err := tpm2.ReadPublic(t.rwc, pHnd)
if err == nil {
// Found the persistent handle, assume it's the key we want.
return pHnd, false, nil
}
rerr := err // Preserve this failure for later logging, if needed

var keyHnd tpmutil.Handle
switch pHnd {
case commonSrkEquivalentHandle:
keyHnd, _, err = tpm2.CreatePrimary(t.rwc, tpm2.HandleOwner, tpm2.PCRSelection{}, "", "", defaultSRKTemplate)
case commonRSAEkEquivalentHandle:
keyHnd, _, err = tpm2.CreatePrimary(t.rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", t.rsaEkTemplate())
}
keyHnd, _, err := tpm2.CreatePrimary(t.rwc, tpm2.HandleOwner, tpm2.PCRSelection{}, "", "", defaultSRKTemplate)
if err != nil {
return 0, false, fmt.Errorf("ReadPublic failed (%v), and then CreatePrimary failed: %v", rerr, err)
}
Expand Down Expand Up @@ -126,7 +162,7 @@ func (t *wrappedTPM20) ekCertificates() ([]EK, error) {
func (t *wrappedTPM20) eks() ([]EK, error) {
if cert, err := readEKCertFromNVRAM20(t.rwc, nvramRSACertIndex); err == nil {
return []EK{
{Public: crypto.PublicKey(cert.PublicKey), Certificate: cert},
{Public: crypto.PublicKey(cert.PublicKey), Certificate: cert, handle: commonRSAEkEquivalentHandle},
}, nil
}

Expand All @@ -150,13 +186,14 @@ func (t *wrappedTPM20) eks() ([]EK, error) {
E: int(pub.RSAParameters.Exponent()),
N: pub.RSAParameters.Modulus(),
},
handle: commonRSAEkEquivalentHandle,
},
}, nil
}

func (t *wrappedTPM20) newAK(opts *AKConfig) (*AK, error) {
// TODO(jsonp): Abstract choice of hierarchy & parent.
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
srk, _, err := t.getStorageRootKeyHandle(commonSrkEquivalentHandle)
if err != nil {
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
}
Expand All @@ -181,7 +218,11 @@ func (t *wrappedTPM20) newAK(opts *AKConfig) (*AK, error) {
if err != nil {
return nil, fmt.Errorf("CertifyCreation failed: %v", err)
}
return &AK{ak: newWrappedAK20(keyHandle, blob, pub, creationData, attestation, sig)}, nil
var ek *EK
if opts != nil {
ek = opts.EK
}
return &AK{ak: newWrappedAK20(keyHandle, blob, pub, creationData, attestation, sig), ek: ek}, nil
}

func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
Expand Down Expand Up @@ -228,7 +269,7 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
}

func createKey(t *wrappedTPM20, opts *KeyConfig) (tpmutil.Handle, []byte, []byte, []byte, error) {
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
srk, _, err := t.getStorageRootKeyHandle(commonSrkEquivalentHandle)
if err != nil {
return 0, nil, nil, nil, fmt.Errorf("failed to get SRK handle: %v", err)
}
Expand Down Expand Up @@ -302,7 +343,7 @@ func (t *wrappedTPM20) deserializeAndLoad(opaqueBlob []byte) (tpmutil.Handle, *s
return 0, nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding)
}

srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
srk, _, err := t.getStorageRootKeyHandle(commonSrkEquivalentHandle)
if err != nil {
return 0, nil, fmt.Errorf("failed to get SRK handle: %v", err)
}
Expand Down Expand Up @@ -413,7 +454,7 @@ func (k *wrappedKey20) close(t tpmBase) error {
return tpm2.FlushContext(tpm.rwc, k.hnd)
}

func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential) ([]byte, error) {
func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) {
t, ok := tb.(*wrappedTPM20)
if !ok {
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
Expand All @@ -428,7 +469,7 @@ func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential) ([
}
secret := in.Secret[2:]

ekHnd, _, err := t.getPrimaryKeyHandle(commonRSAEkEquivalentHandle)
ekHnd, _, err := t.getEndorsementKeyHandle(ek)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit d292432

Please sign in to comment.