mirror of
https://github.com/google/go-attestation.git
synced 2025-02-15 06:41: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.
|
// If nil, the default SRK (i.e. RSA with handle 0x81000001) is assumed.
|
||||||
// Supported only by TPM 2.0 on Linux.
|
// Supported only by TPM 2.0 on Linux.
|
||||||
Parent *ParentKeyConfig
|
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.
|
// defaultConfig is used when no other configuration is specified.
|
||||||
|
@ -100,6 +100,22 @@ func testKeyCreateAndLoad(t *testing.T, tpm *TPM) {
|
|||||||
Size: 2048,
|
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) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
sk, err := tpm.NewKey(ak, test.opts)
|
sk, err := tpm.NewKey(ak, test.opts)
|
||||||
|
@ -117,7 +117,7 @@ type ak interface {
|
|||||||
activateCredential(tpm tpmBase, in EncryptedCredential, ek *EK) ([]byte, error)
|
activateCredential(tpm tpmBase, in EncryptedCredential, ek *EK) ([]byte, error)
|
||||||
quote(t tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error)
|
quote(t tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error)
|
||||||
attestationParameters() AttestationParameters
|
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.
|
// 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
|
// key. Depending on the actual instantiation it can accept different handle
|
||||||
// types (e.g., tpmutil.Handle on Linux or uintptr on Windows).
|
// types (e.g., tpmutil.Handle on Linux or uintptr on Windows).
|
||||||
func (k *AK) Certify(tpm *TPM, handle interface{}) (*CertificationParameters, error) {
|
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.
|
// AKConfig encapsulates parameters for minting keys.
|
||||||
|
@ -83,6 +83,12 @@ type ActivateOpts struct {
|
|||||||
VerifierKeyNameDigest *tpm2.HashValue
|
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.
|
// 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.
|
// 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) {
|
func NewActivateOpts(verifierPubKey tpm2.Public, ek crypto.PublicKey) (*ActivateOpts, error) {
|
||||||
@ -241,9 +247,9 @@ func (p *CertificationParameters) Generate(rnd io.Reader, verifyOpts VerifyOpts,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// certify uses AK's handle and the passed signature scheme to certify the key
|
// certify uses AK's handle, the passed user qualifying data, and the passed
|
||||||
// with the `hnd` handle.
|
// signature scheme to certify the key with the `hnd` handle.
|
||||||
func certify(tpm io.ReadWriteCloser, hnd, akHnd tpmutil.Handle, scheme tpm2.SigScheme) (*CertificationParameters, error) {
|
func certify(tpm io.ReadWriteCloser, hnd, akHnd tpmutil.Handle, qualifyingData []byte, scheme tpm2.SigScheme) (*CertificationParameters, error) {
|
||||||
pub, _, _, err := tpm2.ReadPublic(tpm, hnd)
|
pub, _, _, err := tpm2.ReadPublic(tpm, hnd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tpm2.ReadPublic() failed: %v", err)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not encode public key: %v", err)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tpm2.Certify() failed: %v", err)
|
return nil, fmt.Errorf("tpm2.Certify() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
@ -224,6 +225,15 @@ func TestTPM20KeyCertificationECC(t *testing.T) {
|
|||||||
testKeyCertification(t, tpm, ECDSA)
|
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) {
|
func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
||||||
ak, err := tpm.NewAK(&AKConfig{Algorithm: akAlg})
|
ak, err := tpm.NewAK(&AKConfig{Algorithm: akAlg})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -249,6 +259,7 @@ func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
|||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
name string
|
name string
|
||||||
opts *KeyConfig
|
opts *KeyConfig
|
||||||
|
wantExtraData []byte
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -296,6 +307,26 @@ func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
|||||||
},
|
},
|
||||||
err: nil,
|
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) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
sk, err := tpm.NewKey(ak, test.opts)
|
sk, err := tpm.NewKey(ak, test.opts)
|
||||||
@ -304,6 +335,9 @@ func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
|
|||||||
}
|
}
|
||||||
defer sk.Close()
|
defer sk.Close()
|
||||||
p := sk.CertificationParameters()
|
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)
|
err = p.Verify(verifyOpts)
|
||||||
if test.err == nil && err == nil {
|
if test.err == nil && err == nil {
|
||||||
return
|
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")
|
return nil, fmt.Errorf("not implemented")
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (k *windowsKey12) attestationParameters() AttestationParameters {
|
|||||||
Public: k.public,
|
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")
|
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)
|
t, ok := tb.(*windowsTPM)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("expected *windowsTPM, got %T", tb)
|
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,
|
Alg: tpm2.AlgRSASSA,
|
||||||
Hash: tpm2.AlgSHA1, // PCP-created AK uses SHA1
|
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
|
// 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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ak.Certify() failed: %v", err)
|
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)
|
t, ok := tb.(*wrappedTPM20)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get signature scheme: %v", err)
|
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) {
|
func (k *wrappedKey20) quote(tb tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user