mirror of
https://github.com/google/go-attestation.git
synced 2025-02-14 22:31:56 +00:00
attest: Support "qualifyingData" when creating a new key. (#401)
This commit is contained in:
parent
c7aee80c5d
commit
dfabc9c919
@ -76,6 +76,10 @@ type KeyConfig struct {
|
||||
// If nil, the default SRK (i.e. RSA with handle 0x81000001) is assumed.
|
||||
// Supported only by TPM 2.0 on Linux.
|
||||
Parent *ParentKeyConfig
|
||||
// QualifyingData is an optional data that will be included into
|
||||
// a TPM-generated signature of the minted key.
|
||||
// It may contain any data chosen by the caller.
|
||||
QualifyingData []byte
|
||||
}
|
||||
|
||||
// defaultConfig is used when no other configuration is specified.
|
||||
|
@ -100,6 +100,22 @@ func testKeyCreateAndLoad(t *testing.T, tpm *TPM) {
|
||||
Size: 2048,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "QualifyingData-RSA",
|
||||
opts: &KeyConfig{
|
||||
Algorithm: RSA,
|
||||
Size: 2048,
|
||||
QualifyingData: []byte("qualifying data"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "QualifyingData-ECDSA",
|
||||
opts: &KeyConfig{
|
||||
Algorithm: ECDSA,
|
||||
Size: 256,
|
||||
QualifyingData: []byte("qualifying data"),
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
sk, err := tpm.NewKey(ak, test.opts)
|
||||
|
@ -117,7 +117,7 @@ type ak interface {
|
||||
activateCredential(tpm tpmBase, in EncryptedCredential, ek *EK) ([]byte, error)
|
||||
quote(t tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error)
|
||||
attestationParameters() AttestationParameters
|
||||
certify(tb tpmBase, handle interface{}) (*CertificationParameters, error)
|
||||
certify(tb tpmBase, handle interface{}, opts CertifyOpts) (*CertificationParameters, error)
|
||||
}
|
||||
|
||||
// AK represents a key which can be used for attestation.
|
||||
@ -185,7 +185,7 @@ func (k *AK) AttestationParameters() AttestationParameters {
|
||||
// key. Depending on the actual instantiation it can accept different handle
|
||||
// types (e.g., tpmutil.Handle on Linux or uintptr on Windows).
|
||||
func (k *AK) Certify(tpm *TPM, handle interface{}) (*CertificationParameters, error) {
|
||||
return k.ak.certify(tpm.tpm, handle)
|
||||
return k.ak.certify(tpm.tpm, handle, CertifyOpts{})
|
||||
}
|
||||
|
||||
// AKConfig encapsulates parameters for minting keys.
|
||||
|
@ -83,6 +83,12 @@ type ActivateOpts struct {
|
||||
VerifierKeyNameDigest *tpm2.HashValue
|
||||
}
|
||||
|
||||
// CertifyOpts specifies options for the key's certification.
|
||||
type CertifyOpts struct {
|
||||
// QualifyingData is the user provided qualifying data.
|
||||
QualifyingData []byte
|
||||
}
|
||||
|
||||
// NewActivateOpts creates options for use in generating an activation challenge for a certified key.
|
||||
// The computed hash is the name digest of the public key used to verify the certification of our key.
|
||||
func NewActivateOpts(verifierPubKey tpm2.Public, ek crypto.PublicKey) (*ActivateOpts, error) {
|
||||
@ -241,9 +247,9 @@ func (p *CertificationParameters) Generate(rnd io.Reader, verifyOpts VerifyOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// certify uses AK's handle and the passed signature scheme to certify the key
|
||||
// with the `hnd` handle.
|
||||
func certify(tpm io.ReadWriteCloser, hnd, akHnd tpmutil.Handle, scheme tpm2.SigScheme) (*CertificationParameters, error) {
|
||||
// certify uses AK's handle, the passed user qualifying data, and the passed
|
||||
// signature scheme to certify the key with the `hnd` handle.
|
||||
func certify(tpm io.ReadWriteCloser, hnd, akHnd tpmutil.Handle, qualifyingData []byte, scheme tpm2.SigScheme) (*CertificationParameters, error) {
|
||||
pub, _, _, err := tpm2.ReadPublic(tpm, hnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tpm2.ReadPublic() failed: %v", err)
|
||||
@ -252,7 +258,7 @@ func certify(tpm io.ReadWriteCloser, hnd, akHnd tpmutil.Handle, scheme tpm2.SigS
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not encode public key: %v", err)
|
||||
}
|
||||
att, sig, err := tpm2.CertifyEx(tpm, "", "", hnd, akHnd, nil, scheme)
|
||||
att, sig, err := tpm2.CertifyEx(tpm, "", "", hnd, akHnd, qualifyingData, scheme)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tpm2.Certify() failed: %v", err)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@ -224,6 +225,15 @@ func TestTPM20KeyCertificationECC(t *testing.T) {
|
||||
testKeyCertification(t, tpm, ECDSA)
|
||||
}
|
||||
|
||||
func extraData(t *testing.T, p CertificationParameters) []byte {
|
||||
t.Helper()
|
||||
ad, err := tpm2.DecodeAttestationData(p.CreateAttestation)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode attestation data: %v", err)
|
||||
}
|
||||
return ad.ExtraData
|
||||
}
|
||||
|
||||
func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
||||
ak, err := tpm.NewAK(&AKConfig{Algorithm: akAlg})
|
||||
if err != nil {
|
||||
@ -249,6 +259,7 @@ func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
opts *KeyConfig
|
||||
wantExtraData []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@ -296,6 +307,26 @@ func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "QualifyingData-RSA",
|
||||
opts: &KeyConfig{
|
||||
Algorithm: RSA,
|
||||
Size: 2048,
|
||||
QualifyingData: []byte("qualifying data"),
|
||||
},
|
||||
wantExtraData: []byte("qualifying data"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "QualifyingData-ECDSA",
|
||||
opts: &KeyConfig{
|
||||
Algorithm: ECDSA,
|
||||
Size: 384,
|
||||
QualifyingData: []byte("qualifying data"),
|
||||
},
|
||||
wantExtraData: []byte("qualifying data"),
|
||||
err: nil,
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
sk, err := tpm.NewKey(ak, test.opts)
|
||||
@ -304,6 +335,9 @@ func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
||||
}
|
||||
defer sk.Close()
|
||||
p := sk.CertificationParameters()
|
||||
if gotExtraData, wantExtraData := extraData(t, p), test.wantExtraData; !slices.Equal(gotExtraData, wantExtraData) {
|
||||
t.Errorf("ExtraData got = %v, want = %v", gotExtraData, wantExtraData)
|
||||
}
|
||||
err = p.Verify(verifyOpts)
|
||||
if test.err == nil && err == nil {
|
||||
return
|
||||
|
@ -96,6 +96,6 @@ func (k *trousersKey12) attestationParameters() AttestationParameters {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *trousersKey12) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
func (k *trousersKey12) certify(tb tpmBase, handle interface{}, _ CertifyOpts) (*CertificationParameters, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ func (k *windowsKey12) attestationParameters() AttestationParameters {
|
||||
Public: k.public,
|
||||
}
|
||||
}
|
||||
func (k *windowsKey12) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
func (k *windowsKey12) certify(tb tpmBase, handle interface{}, _ CertifyOpts) (*CertificationParameters, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ func (k *windowsKey20) attestationParameters() AttestationParameters {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *windowsKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
func (k *windowsKey20) certify(tb tpmBase, handle interface{}, _ CertifyOpts) (*CertificationParameters, error) {
|
||||
t, ok := tb.(*windowsTPM)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected *windowsTPM, got %T", tb)
|
||||
@ -210,5 +210,5 @@ func (k *windowsKey20) certify(tb tpmBase, handle interface{}) (*CertificationPa
|
||||
Alg: tpm2.AlgRSASSA,
|
||||
Hash: tpm2.AlgSHA1, // PCP-created AK uses SHA1
|
||||
}
|
||||
return certify(tpm, hnd, akHnd, scheme)
|
||||
return certify(tpm, hnd, akHnd, nil, scheme)
|
||||
}
|
||||
|
@ -302,7 +302,8 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
|
||||
}()
|
||||
|
||||
// Certify application key by AK
|
||||
cp, err := k.certify(t, keyHandle)
|
||||
certifyOpts := CertifyOpts{QualifyingData: opts.QualifyingData}
|
||||
cp, err := k.certify(t, keyHandle, certifyOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ak.Certify() failed: %v", err)
|
||||
}
|
||||
@ -587,7 +588,7 @@ func sigSchemeFromPublicKey(pub []byte) (tpm2.SigScheme, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
func (k *wrappedKey20) certify(tb tpmBase, handle interface{}, opts CertifyOpts) (*CertificationParameters, error) {
|
||||
t, ok := tb.(*wrappedTPM20)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
||||
@ -600,7 +601,7 @@ func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationPa
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get signature scheme: %v", err)
|
||||
}
|
||||
return certify(t.rwc, hnd, k.hnd, scheme)
|
||||
return certify(t.rwc, hnd, k.hnd, opts.QualifyingData, scheme)
|
||||
}
|
||||
|
||||
func (k *wrappedKey20) quote(tb tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user