attest: tpm.NewKeyCertifiedBy() method that does not need an entire attest.AK object. The new method only needs the AK handle and its algorithm. (#402)
Some checks failed
CodeQL / Analyze (go) (push) Has been cancelled
Test / test-linux (1.22.x) (push) Has been cancelled
Test / test-linux-tpm12 (1.22.x) (push) Has been cancelled
Test / test-macos (1.22.x) (push) Has been cancelled
Test / test-windows (1.22.x) (push) Has been cancelled

This commit is contained in:
zhsh 2025-02-03 14:24:55 +11:00 committed by GitHub
parent dfabc9c919
commit 9cdb0fcd55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 76 additions and 13 deletions

View File

@ -364,6 +364,7 @@ type tpmBase interface {
loadKey(opaqueBlob []byte) (*Key, error) loadKey(opaqueBlob []byte) (*Key, error)
loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*Key, error) loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*Key, error)
newKey(ak *AK, opts *KeyConfig) (*Key, error) newKey(ak *AK, opts *KeyConfig) (*Key, error)
newKeyCertifiedByKey(ck certifyingKey, opts *KeyConfig) (*Key, error)
pcrs(alg HashAlg) ([]PCR, error) pcrs(alg HashAlg) ([]PCR, error)
measurementLog() ([]byte, error) measurementLog() ([]byte, error)
} }
@ -449,6 +450,22 @@ func (t *TPM) NewKey(ak *AK, opts *KeyConfig) (*Key, error) {
return t.tpm.newKey(ak, opts) return t.tpm.newKey(ak, opts)
} }
// NewKeyCertifiedByKey creates an application key certified by
// the attestation key. Unlike NewKey(), this method does not require
// an attest.AK object and only requires the AK handle and its algorithm.
// Thus it can be used in cases where the attestation key was not created
// by go-attestation library. If opts is nil then DefaultConfig is used.
func (t *TPM) NewKeyCertifiedByKey(akHandle tpmutil.Handle, akAlg Algorithm, opts *KeyConfig) (*Key, error) {
if opts == nil {
opts = defaultConfig
}
if opts.Algorithm == "" && opts.Size == 0 {
opts = defaultConfig
}
ck := certifyingKey{handle: akHandle, alg: akAlg}
return t.tpm.newKeyCertifiedByKey(ck, opts)
}
// LoadKey loads a previously-created application key into the TPM for use. // LoadKey loads a previously-created application key into the TPM for use.
// A key loaded via this function needs to be closed with .Close(). // A key loaded via this function needs to be closed with .Close().
// Only blobs generated by calling Key.Marshal() are valid parameters // Only blobs generated by calling Key.Marshal() are valid parameters

View File

@ -112,6 +112,10 @@ func (t *trousersTPM) newKey(*AK, *KeyConfig) (*Key, error) {
return nil, fmt.Errorf("not implemented") return nil, fmt.Errorf("not implemented")
} }
func (t *trousersTPM) newKeyCertifiedByKey(ck certifyingKey, opts *KeyConfig) (*Key, error) {
return nil, fmt.Errorf("not implemented")
}
func (t *trousersTPM) loadKey(opaqueBlob []byte) (*Key, error) { func (t *trousersTPM) loadKey(opaqueBlob []byte) (*Key, error) {
return nil, fmt.Errorf("not implemented") return nil, fmt.Errorf("not implemented")
} }

View File

@ -345,6 +345,10 @@ func (t *windowsTPM) newKey(*AK, *KeyConfig) (*Key, error) {
return nil, fmt.Errorf("not implemented") return nil, fmt.Errorf("not implemented")
} }
func (t *windowsTPM) newKeyCertifiedByKey(ck certifyingKey, opts *KeyConfig) (*Key, error) {
return nil, fmt.Errorf("not implemented")
}
func (t *windowsTPM) loadKey(opaqueBlob []byte) (*Key, error) { func (t *windowsTPM) loadKey(opaqueBlob []byte) (*Key, error) {
return nil, fmt.Errorf("not implemented") return nil, fmt.Errorf("not implemented")
} }

View File

@ -38,6 +38,12 @@ type wrappedTPM20 struct {
tpmECCEkTemplate *tpm2.Public tpmECCEkTemplate *tpm2.Public
} }
// certifyingKey contains details of a TPM key that could certify other keys.
type certifyingKey struct {
handle tpmutil.Handle
alg Algorithm
}
func (t *wrappedTPM20) rsaEkTemplate() tpm2.Public { func (t *wrappedTPM20) rsaEkTemplate() tpm2.Public {
if t.tpmRSAEkTemplate != nil { if t.tpmRSAEkTemplate != nil {
return *t.tpmRSAEkTemplate return *t.tpmRSAEkTemplate
@ -285,6 +291,15 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
return nil, fmt.Errorf("expected *wrappedKey20, got: %T", k) return nil, fmt.Errorf("expected *wrappedKey20, got: %T", k)
} }
kAlg, err := k.algorithm()
if err != nil {
return nil, fmt.Errorf("get algorithm: %v", err)
}
ck := certifyingKey{handle: k.hnd, alg: kAlg}
return t.newKeyCertifiedByKey(ck, opts)
}
func (t *wrappedTPM20) newKeyCertifiedByKey(ck certifyingKey, opts *KeyConfig) (*Key, error) {
parent, blob, pub, creationData, err := createKey(t, opts) parent, blob, pub, creationData, err := createKey(t, opts)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot create key: %v", err) return nil, fmt.Errorf("cannot create key: %v", err)
@ -303,9 +318,9 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
// Certify application key by AK // Certify application key by AK
certifyOpts := CertifyOpts{QualifyingData: opts.QualifyingData} certifyOpts := CertifyOpts{QualifyingData: opts.QualifyingData}
cp, err := k.certify(t, keyHandle, certifyOpts) cp, err := certifyByKey(t, keyHandle, ck, certifyOpts)
if err != nil { if err != nil {
return nil, fmt.Errorf("ak.Certify() failed: %v", err) return nil, fmt.Errorf("certifyByKey() failed: %v", err)
} }
if !bytes.Equal(pub, cp.Public) { if !bytes.Equal(pub, cp.Public) {
return nil, fmt.Errorf("certified incorrect key, expected: %v, certified: %v", pub, cp.Public) return nil, fmt.Errorf("certified incorrect key, expected: %v, certified: %v", pub, cp.Public)
@ -567,28 +582,36 @@ func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential, ek
}, k.hnd, ekHnd, credential, secret) }, k.hnd, ekHnd, credential, secret)
} }
func sigSchemeFromPublicKey(pub []byte) (tpm2.SigScheme, error) { func sigSchemeFromAlgorithm(alg Algorithm) (tpm2.SigScheme, error) {
tpmPub, err := tpm2.DecodePublic(pub) switch alg {
if err != nil { case RSA:
return tpm2.SigScheme{}, fmt.Errorf("decode public key: %v", err)
}
switch tpmPub.Type {
case tpm2.AlgRSA:
return tpm2.SigScheme{ return tpm2.SigScheme{
Alg: tpm2.AlgRSASSA, Alg: tpm2.AlgRSASSA,
Hash: tpm2.AlgSHA256, Hash: tpm2.AlgSHA256,
}, nil }, nil
case tpm2.AlgECC: case ECDSA:
return tpm2.SigScheme{ return tpm2.SigScheme{
Alg: tpm2.AlgECDSA, Alg: tpm2.AlgECDSA,
Hash: tpm2.AlgSHA256, Hash: tpm2.AlgSHA256,
}, nil }, nil
default: default:
return tpm2.SigScheme{}, fmt.Errorf("public key of alg 0x%x not supported", tpmPub.Type) return tpm2.SigScheme{}, fmt.Errorf("algorithm %v not supported", alg)
} }
} }
func (k *wrappedKey20) certify(tb tpmBase, handle interface{}, opts CertifyOpts) (*CertificationParameters, error) { func (k *wrappedKey20) certify(tb tpmBase, handle interface{}, opts CertifyOpts) (*CertificationParameters, error) {
kAlg, err := k.algorithm()
if err != nil {
return nil, fmt.Errorf("unknown algorithm: %v", err)
}
ck := certifyingKey{
handle: k.hnd,
alg: kAlg,
}
return certifyByKey(tb, handle, ck, opts)
}
func certifyByKey(tb tpmBase, handle interface{}, ck certifyingKey, 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)
@ -597,11 +620,11 @@ func (k *wrappedKey20) certify(tb tpmBase, handle interface{}, opts CertifyOpts)
if !ok { if !ok {
return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle) return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle)
} }
scheme, err := sigSchemeFromPublicKey(k.public) scheme, err := sigSchemeFromAlgorithm(ck.alg)
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, opts.QualifyingData, scheme) return certify(t.rwc, hnd, ck.handle, 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) {
@ -707,3 +730,18 @@ func (k *wrappedKey20) decrypt(tb tpmBase, ctxt []byte) ([]byte, error) {
func (k *wrappedKey20) blobs() ([]byte, []byte, error) { func (k *wrappedKey20) blobs() ([]byte, []byte, error) {
return k.public, k.blob, nil return k.public, k.blob, nil
} }
func (k *wrappedKey20) algorithm() (Algorithm, error) {
tpmPub, err := tpm2.DecodePublic(k.public)
if err != nil {
return "", fmt.Errorf("decode public key: %v", err)
}
switch tpmPub.Type {
case tpm2.AlgRSA:
return RSA, nil
case tpm2.AlgECC:
return ECDSA, nil
default:
return "", fmt.Errorf("unsupported key type: %v", tpmPub.Type)
}
}