mirror of
https://github.com/google/go-attestation.git
synced 2025-03-22 20:15:34 +00:00
Add AK.Certify() and use CertifyEx() for certification (#210)
* replace CertifyCreation() by CertifyEx() to handle certification of objects for which we cannot extract CreationData * add AK.Certify(handle) allowing to certify externally-created keys
This commit is contained in:
parent
e24a847d44
commit
6848928436
@ -103,6 +103,7 @@ type ak interface {
|
||||
activateCredential(tpm tpmBase, in EncryptedCredential) ([]byte, error)
|
||||
quote(t tpmBase, nonce []byte, alg HashAlg) (*Quote, error)
|
||||
attestationParameters() AttestationParameters
|
||||
certify(tb tpmBase, handle interface{}) (*CertificationParameters, error)
|
||||
}
|
||||
|
||||
// AK represents a key which can be used for attestation.
|
||||
@ -145,6 +146,14 @@ func (k *AK) AttestationParameters() AttestationParameters {
|
||||
return k.ak.attestationParameters()
|
||||
}
|
||||
|
||||
// Certify uses the attestation key to certify the key with `handle`. It returns
|
||||
// certification parameters which allow to verify the properties of the attested
|
||||
// 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)
|
||||
}
|
||||
|
||||
// AKConfig encapsulates parameters for minting keys. This type is defined
|
||||
// now (despite being empty) for future interface compatibility.
|
||||
type AKConfig struct {
|
||||
|
@ -20,8 +20,10 @@ import (
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
)
|
||||
|
||||
// secureCurves represents a set of secure elliptic curves. For now,
|
||||
@ -32,7 +34,6 @@ var secureCurves = map[tpm2.EllipticCurve]bool{
|
||||
tpm2.CurveNISTP521: true,
|
||||
tpm2.CurveBNP256: true,
|
||||
tpm2.CurveBNP638: true,
|
||||
tpm2.CurveSM2P256: true,
|
||||
}
|
||||
|
||||
// CertificationParameters encapsulates the inputs for certifying an application key.
|
||||
@ -73,16 +74,12 @@ func (p *CertificationParameters) Verify(opts VerifyOpts) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("DecodePublic() failed: %v", err)
|
||||
}
|
||||
_, err = tpm2.DecodeCreationData(p.CreateData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("DecodeCreationData() failed: %v", err)
|
||||
}
|
||||
att, err := tpm2.DecodeAttestationData(p.CreateAttestation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("DecodeAttestationData() failed: %v", err)
|
||||
}
|
||||
if att.Type != tpm2.TagAttestCreation {
|
||||
return fmt.Errorf("attestation does not apply to creation data, got tag %x", att.Type)
|
||||
if att.Type != tpm2.TagAttestCertify {
|
||||
return fmt.Errorf("attestation does not apply to certification data, got tag %x", att.Type)
|
||||
}
|
||||
|
||||
switch pub.Type {
|
||||
@ -98,18 +95,6 @@ func (p *CertificationParameters) Verify(opts VerifyOpts) error {
|
||||
return fmt.Errorf("public key of alg 0x%x not supported", pub.Type)
|
||||
}
|
||||
|
||||
// Compute & verify that the creation data matches the digest in the
|
||||
// attestation structure.
|
||||
nameHash, err := pub.NameAlg.Hash()
|
||||
if err != nil {
|
||||
return fmt.Errorf("HashConstructor() failed: %v", err)
|
||||
}
|
||||
h := nameHash.New()
|
||||
h.Write(p.CreateData)
|
||||
if !bytes.Equal(att.AttestedCreationInfo.OpaqueDigest, h.Sum(nil)) {
|
||||
return errors.New("attestation refers to different public key")
|
||||
}
|
||||
|
||||
// Make sure the key has sane parameters (e.g., attestation can be faked if an AK
|
||||
// can be used for arbitrary signatures).
|
||||
// We verify the following:
|
||||
@ -136,19 +121,19 @@ func (p *CertificationParameters) Verify(opts VerifyOpts) error {
|
||||
|
||||
// Verify the attested creation name matches what is computed from
|
||||
// the public key.
|
||||
match, err := att.AttestedCreationInfo.Name.MatchesPublic(pub)
|
||||
match, err := att.AttestedCertifyInfo.Name.MatchesPublic(pub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !match {
|
||||
return errors.New("creation attestation refers to a different key")
|
||||
return errors.New("certification refers to a different key")
|
||||
}
|
||||
|
||||
// Check the signature over the attestation data verifies correctly.
|
||||
// TODO: Support ECC certifying keys
|
||||
pk, ok := opts.Public.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("Only RSA verification keys are supported")
|
||||
return fmt.Errorf("only RSA verification keys are supported")
|
||||
}
|
||||
if !opts.Hash.Available() {
|
||||
return fmt.Errorf("hash function is unavailable")
|
||||
@ -171,3 +156,29 @@ func (p *CertificationParameters) Verify(opts VerifyOpts) error {
|
||||
|
||||
return 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) {
|
||||
pub, _, _, err := tpm2.ReadPublic(tpm, hnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tpm2.ReadPublic() failed: %v", err)
|
||||
}
|
||||
public, err := pub.Encode()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not encode public key: %v", err)
|
||||
}
|
||||
att, sig, err := tpm2.CertifyEx(tpm, "", "", hnd, akHnd, nil, scheme)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tpm2.Certify() failed: %v", err)
|
||||
}
|
||||
signature, err := tpmutil.Pack(scheme.Alg, scheme.Hash, tpmutil.U16Bytes(sig))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to pack TPMT_SIGNATURE: %v", err)
|
||||
}
|
||||
return &CertificationParameters{
|
||||
Public: public,
|
||||
CreateAttestation: att,
|
||||
CreateSignature: signature,
|
||||
}, nil
|
||||
}
|
||||
|
@ -110,18 +110,6 @@ func TestCertificationParametersTPM20(t *testing.T) {
|
||||
name: "modified Public",
|
||||
p: &CertificationParameters{
|
||||
Public: akAttestParams.Public,
|
||||
CreateData: skCertParams.CreateData,
|
||||
CreateAttestation: skCertParams.CreateAttestation,
|
||||
CreateSignature: skCertParams.CreateSignature,
|
||||
},
|
||||
opts: correctOpts,
|
||||
err: cmpopts.AnyError,
|
||||
},
|
||||
{
|
||||
name: "modified CreateData",
|
||||
p: &CertificationParameters{
|
||||
Public: skCertParams.Public,
|
||||
CreateData: []byte("unparsable"),
|
||||
CreateAttestation: skCertParams.CreateAttestation,
|
||||
CreateSignature: skCertParams.CreateSignature,
|
||||
},
|
||||
@ -132,7 +120,6 @@ func TestCertificationParametersTPM20(t *testing.T) {
|
||||
name: "modified CreateAttestation",
|
||||
p: &CertificationParameters{
|
||||
Public: skCertParams.Public,
|
||||
CreateData: skCertParams.CreateData,
|
||||
CreateAttestation: akAttestParams.CreateAttestation,
|
||||
CreateSignature: skCertParams.CreateSignature,
|
||||
},
|
||||
@ -143,7 +130,6 @@ func TestCertificationParametersTPM20(t *testing.T) {
|
||||
name: "modified CreateSignature",
|
||||
p: &CertificationParameters{
|
||||
Public: skCertParams.Public,
|
||||
CreateData: skCertParams.CreateData,
|
||||
CreateAttestation: skCertParams.CreateAttestation,
|
||||
CreateSignature: akAttestParams.CreateSignature,
|
||||
},
|
||||
|
@ -91,3 +91,7 @@ func (k *trousersKey12) attestationParameters() AttestationParameters {
|
||||
UseTCSDActivationFormat: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *trousersKey12) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
tpm1 "github.com/google/go-tpm/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// windowsKey12 represents a Windows-managed key on a TPM1.2 TPM.
|
||||
@ -110,6 +111,9 @@ func (k *windowsKey12) attestationParameters() AttestationParameters {
|
||||
Public: k.public,
|
||||
}
|
||||
}
|
||||
func (k *windowsKey12) certify(tb tpmBase, handle Handle) (*CertificationParameters, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
// windowsKey20 represents a key bound to a TPM 2.0.
|
||||
type windowsKey20 struct {
|
||||
@ -184,3 +188,31 @@ func (k *windowsKey20) attestationParameters() AttestationParameters {
|
||||
CreateSignature: k.createSignature,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *windowsKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
t, ok := tb.(*windowsTPM)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected *windowsTPM, got %T", tb)
|
||||
}
|
||||
h, ok := handle.(uintptr)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected uinptr, got %T", handle)
|
||||
}
|
||||
hnd, err := t.pcp.TPMKeyHandle(h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err)
|
||||
}
|
||||
akHnd, err := t.pcp.TPMKeyHandle(k.hnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err)
|
||||
}
|
||||
tpm, err := t.pcp.TPMCommandInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err)
|
||||
}
|
||||
scheme := tpm2.SigScheme{
|
||||
Alg: tpm2.AlgRSASSA,
|
||||
Hash: tpm2.AlgSHA1, // PCP-created AK uses SHA1
|
||||
}
|
||||
return certify(tpm, hnd, akHnd, scheme)
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
package attest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
@ -169,7 +170,7 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
|
||||
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
||||
}
|
||||
|
||||
blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", eccKeyTemplate)
|
||||
blob, pub, creationData, _, _, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", eccKeyTemplate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreateKey() failed: %v", err)
|
||||
}
|
||||
@ -185,16 +186,15 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
|
||||
}()
|
||||
|
||||
// Certify application key by AK
|
||||
attestation, sig, err := tpm2.CertifyCreation(t.rwc, "", keyHandle, k.hnd, nil, creationHash, tpm2.SigScheme{tpm2.AlgRSASSA, tpm2.AlgSHA256, 0}, tix)
|
||||
cp, err := k.certify(t, keyHandle)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CertifyCreation failed: %v", err)
|
||||
return nil, fmt.Errorf("ak.Certify() failed: %v", err)
|
||||
}
|
||||
// Pack the raw structure into a TPMU_SIGNATURE.
|
||||
signature, err := tpmutil.Pack(tpm2.AlgRSASSA, tpm2.AlgSHA256, tpmutil.U16Bytes(sig))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to pack TPMT_SIGNATURE: %v", err)
|
||||
if !bytes.Equal(pub, cp.Public) {
|
||||
return nil, fmt.Errorf("certified incorrect key, expected: %v, certified: %v", pub, cp.Public)
|
||||
}
|
||||
|
||||
// Pack the raw structure into a TPMU_SIGNATURE.
|
||||
tpmPub, err := tpm2.DecodePublic(pub)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode public key: %v", err)
|
||||
@ -203,7 +203,7 @@ func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("access public key: %v", err)
|
||||
}
|
||||
return &Key{key: newWrappedKey20(keyHandle, blob, pub, creationData, attestation, signature), pub: pubKey, tpm: t}, nil
|
||||
return &Key{key: newWrappedKey20(keyHandle, blob, pub, creationData, cp.CreateAttestation, cp.CreateSignature), pub: pubKey, tpm: t}, nil
|
||||
}
|
||||
|
||||
func (t *wrappedTPM20) deserializeAndLoad(opaqueBlob []byte) (tpmutil.Handle, *serializedKey, error) {
|
||||
@ -370,6 +370,22 @@ func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential) ([
|
||||
}, k.hnd, ekHnd, credential, secret)
|
||||
}
|
||||
|
||||
func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
||||
t, ok := tb.(*wrappedTPM20)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
||||
}
|
||||
hnd, ok := handle.(tpmutil.Handle)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle)
|
||||
}
|
||||
scheme := tpm2.SigScheme{
|
||||
Alg: tpm2.AlgRSASSA,
|
||||
Hash: tpm2.AlgSHA256,
|
||||
}
|
||||
return certify(t.rwc, hnd, k.hnd, scheme)
|
||||
}
|
||||
|
||||
func (k *wrappedKey20) quote(tb tpmBase, nonce []byte, alg HashAlg) (*Quote, error) {
|
||||
t, ok := tb.(*wrappedTPM20)
|
||||
if !ok {
|
||||
@ -390,7 +406,6 @@ func (k *wrappedKey20) attestationParameters() AttestationParameters {
|
||||
func (k *wrappedKey20) certificationParameters() CertificationParameters {
|
||||
return CertificationParameters{
|
||||
Public: k.public,
|
||||
CreateData: k.createData,
|
||||
CreateAttestation: k.createAttestation,
|
||||
CreateSignature: k.createSignature,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user