mirror of
https://github.com/google/go-attestation.git
synced 2024-12-19 21:17:58 +00:00
Add EK as a field to AK struct. (#332)
The change is a no-op for existing clients, and it will simplify adding the support for ECC EKs. The activation code no longer makes assumptions about EK's type and handle (i.e. RSA and 0x81010001), and instead relies on TPM.EKs() to provide the EK's details.
This commit is contained in:
parent
63dd90f699
commit
d29df30553
@ -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
|
||||
@ -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)
|
||||
@ -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.
|
||||
@ -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.
|
||||
@ -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
|
||||
@ -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
|
||||
|
@ -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 {
|
||||
@ -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("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 srkHnd != commonSrkEquivalentHandle {
|
||||
t.Fatalf("bad SRK-equivalent handle: got 0x%x, wanted 0x%x", srkHnd, commonSrkEquivalentHandle)
|
||||
}
|
||||
|
||||
ekHnd, p, err := tpm.tpm.(*wrappedTPM20).getPrimaryKeyHandle(commonRSAEkEquivalentHandle)
|
||||
srkHnd, p, err := tpm.tpm.(*wrappedTPM20).getStorageRootKeyHandle(commonSrkEquivalentHandle)
|
||||
if err != nil {
|
||||
t.Fatalf("second getPrimaryKeyHandle() failed: %v", err)
|
||||
t.Fatalf("second getStorageRootKeyHandle() failed: %v", err)
|
||||
}
|
||||
if ekHnd != commonRSAEkEquivalentHandle {
|
||||
t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, commonRSAEkEquivalentHandle)
|
||||
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("getStorageRootKeyHandle() failed: %v", err)
|
||||
}
|
||||
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).getEndorsementKeyHandle(&ek)
|
||||
if err != nil {
|
||||
t.Fatalf("second getEndorsementKeyHandle() failed: %v", err)
|
||||
}
|
||||
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")
|
||||
|
@ -16,7 +16,6 @@ package attest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"flag"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
|
@ -83,8 +83,50 @@ 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.
|
||||
@ -92,13 +134,7 @@ func (t *wrappedTPM20) getPrimaryKeyHandle(pHnd tpmutil.Handle) (tpmutil.Handle,
|
||||
}
|
||||
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)
|
||||
}
|
||||
@ -115,7 +151,7 @@ func (t *wrappedTPM20) getPrimaryKeyHandle(pHnd tpmutil.Handle) (tpmutil.Handle,
|
||||
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
|
||||
}
|
||||
|
||||
@ -139,13 +175,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)
|
||||
}
|
||||
@ -170,7 +207,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) {
|
||||
@ -217,7 +258,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)
|
||||
}
|
||||
@ -291,7 +332,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)
|
||||
}
|
||||
@ -402,7 +443,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)
|
||||
@ -417,7 +458,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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user