Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various fixes for Remote Attestation implementations #235

Merged
merged 3 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tpm2/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestEncodeDecodeCreationData(t *testing.T) {
OutsideInfo: []byte{7, 8, 9},
}

encoded, err := cd.encode()
encoded, err := cd.EncodeCreationData()
if err != nil {
t.Fatalf("error encoding CreationData: %v", err)
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func TestDecodeLoad(t *testing.T) {
}

func TestEncodeCreate(t *testing.T) {
testCmdBytes, err := hex.DecodeString("80020000004d00000131400000010000000940000009000001000000090004010203040001FF001a0001000400030072000000060080004300100400000100010000000000000001000403800000")
testCmdBytes, err := hex.DecodeString("80020000004d00000131400000010000000940000009000001000000090004010203040001ff001a000100040003007200000006008000430010040000010001000000045445535400000001000403800000")
if err != nil {
t.Fatal(err)
}
Expand All @@ -188,7 +188,7 @@ func TestEncodeCreate(t *testing.T) {
},
}
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession}
cmdBytes, err := encodeCreate(HandleOwner, pcrSelection7, auth, defaultPassword, []byte{255} /*sensitiveData*/, params)
cmdBytes, err := encodeCreate(HandleOwner, pcrSelection7, auth, defaultPassword, []byte{255} /*sensitiveData*/, params, []byte("TEST") /*OutsideInfo*/)
if err != nil {
t.Fatal(err)
}
Expand Down
25 changes: 22 additions & 3 deletions tpm2/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ func DecodeAttestationData(in []byte) (*AttestationData, error) {
return nil, fmt.Errorf("decoding AttestedQuoteInfo: %v", err)
}
default:
return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
return nil, fmt.Errorf("only Quote, Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
}

return &ad, nil
Expand Down Expand Up @@ -705,8 +705,12 @@ func (ad AttestationData) Encode() ([]byte, error) {
if info, err = ad.AttestedCreationInfo.encode(); err != nil {
return nil, fmt.Errorf("encoding AttestedCreationInfo: %v", err)
}
case TagAttestQuote:
if info, err = ad.AttestedQuoteInfo.encode(); err != nil {
return nil, fmt.Errorf("encoding AttestedQuoteInfo: %v", err)
}
default:
return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
return nil, fmt.Errorf("only Quote, Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
}

return concat(head, signer, tail, info)
Expand Down Expand Up @@ -807,6 +811,20 @@ func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
return &out, nil
}

func (qi QuoteInfo) encode() ([]byte, error) {
sel, err := encodeTPMLPCRSelection(qi.PCRSelection)
if err != nil {
return nil, fmt.Errorf("encoding PCRSelection: %v", err)
}

digest, err := tpmutil.Pack(qi.PCRDigest)
if err != nil {
return nil, fmt.Errorf("encoding PCRDigest: %v", err)
}

return concat(sel, digest)
}

// IDObject represents an encrypted credential bound to a TPM object.
type IDObject struct {
IntegrityHMAC tpmutil.U16Bytes
Expand All @@ -827,7 +845,8 @@ type CreationData struct {
OutsideInfo tpmutil.U16Bytes
}

func (cd *CreationData) encode() ([]byte, error) {
// EncodeCreationData encodes byte array to TPMS_CREATION_DATA message.
func (cd *CreationData) EncodeCreationData() ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be exported?

(Not saying its wrong, but would like to understand the use-case. go-attestation package has been able to handle creation data by simply keeping it as bytes and only decoding when necessary, rather than doing round-trips through encode/decode).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use it to generate TPMS_CREATE_DATA structures for various tests.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the DecodeCreationData is already public. :)

sel, err := encodeTPMLPCRSelection(cd.PCRSelection)
if err != nil {
return nil, fmt.Errorf("encoding PCRSelection: %v", err)
Expand Down
42 changes: 28 additions & 14 deletions tpm2/test/tpm2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"fmt"
"hash"
"io"
"math/big"
"reflect"
"strings"
"testing"
Expand Down Expand Up @@ -610,14 +609,19 @@ func TestCertify(t *testing.T) {
}
defer FlushContext(rw, subjectHandle)

attest, sig, err := Certify(rw, defaultPassword, defaultPassword, subjectHandle, signerHandle, nil)
attest, sigRaw, err := Certify(rw, defaultPassword, defaultPassword, subjectHandle, signerHandle, nil)
if err != nil {
t.Errorf("Certify failed: %s", err)
return
}
sig, err := DecodeSignature(bytes.NewBuffer(sigRaw))
if err != nil {
t.Errorf("DecodeSignature failed: %s", err)
return
}

attestHash := sha256.Sum256(attest)
if err := rsa.VerifyPKCS1v15(signerPub.(*rsa.PublicKey), crypto.SHA256, attestHash[:], sig); err != nil {
if err := rsa.VerifyPKCS1v15(signerPub.(*rsa.PublicKey), crypto.SHA256, attestHash[:], sig.RSA.Signature); err != nil {
t.Errorf("Signature verification failed: %v", err)
}

Expand Down Expand Up @@ -736,14 +740,19 @@ func TestCertifyExternalKey(t *testing.T) {
}
defer FlushContext(rw, subjectHandle)

attest, sig, err := Certify(rw, emptyPassword, defaultPassword, subjectHandle, signerHandle, nil)
attest, sigRaw, err := Certify(rw, emptyPassword, defaultPassword, subjectHandle, signerHandle, nil)
if err != nil {
t.Errorf("Certify failed: %s", err)
return
}
sig, err := DecodeSignature(bytes.NewBuffer(sigRaw))
if err != nil {
t.Errorf("DecodeSignature failed: %s", err)
return
}

attestHash := sha256.Sum256(attest)
if err := rsa.VerifyPKCS1v15(signerPub.(*rsa.PublicKey), crypto.SHA256, attestHash[:], sig); err != nil {
if err := rsa.VerifyPKCS1v15(signerPub.(*rsa.PublicKey), crypto.SHA256, attestHash[:], sig.RSA.Signature); err != nil {
t.Errorf("Signature verification failed: %v", err)
}
}
Expand Down Expand Up @@ -1227,14 +1236,19 @@ func TestCreateAndCertifyCreation(t *testing.T) {
defer FlushContext(rw, keyHandle)

scheme := SigScheme{Alg: AlgRSASSA, Hash: AlgSHA256, Count: 0}
attestation, signature, err := CertifyCreation(rw, emptyPassword, keyHandle, keyHandle, nil, creationHash, scheme, tix)
attestation, sigRaw, err := CertifyCreation(rw, emptyPassword, keyHandle, keyHandle, nil, creationHash, scheme, tix)
if err != nil {
t.Fatalf("CertifyCreation failed: %s", err)
}
att, err := DecodeAttestationData(attestation)
if err != nil {
t.Fatalf("DecodeAttestationData(%v) failed: %v", attestation, err)
}
signature, err := DecodeSignature(bytes.NewBuffer(sigRaw))
if err != nil {
t.Errorf("DecodeSignature failed: %s", err)
return
}
if att.Type != TagAttestCreation {
t.Errorf("Got att.Type = %v, want TagAttestCreation", att.Type)
}
Expand All @@ -1254,7 +1268,7 @@ func TestCreateAndCertifyCreation(t *testing.T) {
rsaPub := rsa.PublicKey{E: int(p.RSAParameters.Exponent()), N: p.RSAParameters.Modulus()}
hsh := crypto.SHA256.New()
hsh.Write(attestation)
if err := rsa.VerifyPKCS1v15(&rsaPub, crypto.SHA256, hsh.Sum(nil), signature); err != nil {
if err := rsa.VerifyPKCS1v15(&rsaPub, crypto.SHA256, hsh.Sum(nil), signature.RSA.Signature); err != nil {
t.Errorf("VerifyPKCS1v15 failed: %v", err)
}
}
Expand All @@ -1281,7 +1295,7 @@ func TestCreateAndCertifyCreationECC(t *testing.T) {
defer FlushContext(rw, keyHandle)

scheme := SigScheme{Alg: AlgECDSA, Hash: AlgSHA256, Count: 0}
attestation, signature, err := CertifyCreation(rw, emptyPassword, keyHandle, keyHandle, nil, creationHash, scheme, tix)
attestation, sigRaw, err := CertifyCreation(rw, emptyPassword, keyHandle, keyHandle, nil, creationHash, scheme, tix)
if err != nil {
t.Fatalf("CertifyCreation failed: %s", err)
}
Expand All @@ -1290,6 +1304,11 @@ func TestCreateAndCertifyCreationECC(t *testing.T) {
if err != nil {
t.Fatalf("DecodeAttestationData(%v) failed: %v", attestation, err)
}
signature, err := DecodeSignature(bytes.NewBuffer(sigRaw))
if err != nil {
t.Errorf("DecodeSignature failed: %s", err)
return
}
if att.Type != TagAttestCreation {
t.Errorf("Got att.Type = %v, want TagAttestCreation", att.Type)
}
Expand Down Expand Up @@ -1317,12 +1336,7 @@ func TestCreateAndCertifyCreationECC(t *testing.T) {
hsh = signHash.New()
hsh.Write(attestation)

r := new(big.Int)
s := new(big.Int)
r.SetBytes(signature[:32])
s.SetBytes(signature[32:])

if !ecdsa.Verify(&pkEcdsa, hsh.Sum(nil), r, s) {
if !ecdsa.Verify(&pkEcdsa, hsh.Sum(nil), signature.ECC.R, signature.ECC.S) {
t.Fatalf("Verify failed")
}
}
Expand Down
51 changes: 20 additions & 31 deletions tpm2/tpm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func encodeSensitiveArea(s tpmsSensitiveCreate) ([]byte, error) {
}

// encodeCreate works for both TPM2_Create and TPM2_CreatePrimary.
func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, ownerPassword string, sensitiveData []byte, pub Public) ([]byte, error) {
func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, ownerPassword string, sensitiveData []byte, pub Public, outsideInfo []byte) ([]byte, error) {
parent, err := tpmutil.Pack(owner)
if err != nil {
return nil, err
Expand All @@ -399,7 +399,7 @@ func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, owne
if err != nil {
return nil, err
}
outsideInfo, err := tpmutil.Pack(tpmutil.U16Bytes(nil))
outsideInfoBlob, err := tpmutil.Pack(tpmutil.U16Bytes(outsideInfo))
if err != nil {
return nil, err
}
Expand All @@ -412,7 +412,7 @@ func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, owne
encodedAuth,
inSensitive,
publicBlob,
outsideInfo,
outsideInfoBlob,
creationPCR,
)
}
Expand Down Expand Up @@ -462,7 +462,7 @@ func CreatePrimary(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, par
// are returned, and they are returned in relatively raw form.
func CreatePrimaryEx(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public) (keyHandle tpmutil.Handle, public, creationData, creationHash []byte, ticket Ticket, creationName []byte, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
Cmd, err := encodeCreate(owner, sel, auth, ownerPassword, nil /*inSensitive*/, pub)
Cmd, err := encodeCreate(owner, sel, auth, ownerPassword, nil /*inSensitive*/, pub, nil /*OutsideInfo*/)
if err != nil {
return 0, nil, nil, nil, Ticket{}, nil, err
}
Expand Down Expand Up @@ -527,8 +527,8 @@ func decodeCreate(in []byte) (private, public, creationData, creationHash tpmuti
return private, public, creationData, creationHash, creationTicket, nil
}

func create(rw io.ReadWriter, parentHandle tpmutil.Handle, auth AuthCommand, objectPassword string, sensitiveData []byte, pub Public, pcrSelection PCRSelection) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
cmd, err := encodeCreate(parentHandle, pcrSelection, auth, objectPassword, sensitiveData, pub)
func create(rw io.ReadWriter, parentHandle tpmutil.Handle, auth AuthCommand, objectPassword string, sensitiveData []byte, pub Public, pcrSelection PCRSelection, outsideInfo []byte) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
cmd, err := encodeCreate(parentHandle, pcrSelection, auth, objectPassword, sensitiveData, pub, outsideInfo)
if err != nil {
return nil, nil, nil, nil, Ticket{}, err
}
Expand All @@ -544,21 +544,28 @@ func create(rw io.ReadWriter, parentHandle tpmutil.Handle, auth AuthCommand, obj
// creation data, a hash of said data and the creation ticket.
func CreateKey(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel)
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel, nil /*OutsideInfo*/)
}

// CreateKeyUsingAuth creates a new key pair under the owner handle using the
// provided AuthCommand. Returns private key and public key blobs as well as
// the creation data, a hash of said data, and the creation ticket.
func CreateKeyUsingAuth(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, ownerPassword string, pub Public) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel)
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel, nil /*OutsideInfo*/)
}

// CreateKeyWithSensitive is very similar to CreateKey, except
// that it can take in a piece of sensitive data.
func CreateKeyWithSensitive(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public, sensitive []byte) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
return create(rw, owner, auth, ownerPassword, sensitive, pub, sel)
return create(rw, owner, auth, ownerPassword, sensitive, pub, sel, nil /*OutsideInfo*/)
}

// CreateKeyWithOutsideInfo is very similar to CreateKey, except
// that it returns the outside information.
func CreateKeyWithOutsideInfo(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public, outsideInfo []byte) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel, outsideInfo)
}

// Seal creates a data blob object that seals the sensitive data under a parent and with a
Expand All @@ -572,7 +579,7 @@ func Seal(rw io.ReadWriter, parentHandle tpmutil.Handle, parentPassword, objectP
AuthPolicy: objectAuthPolicy,
}
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
private, public, _, _, _, err := create(rw, parentHandle, auth, objectPassword, sensitiveData, inPublic, PCRSelection{})
private, public, _, _, _, err := create(rw, parentHandle, auth, objectPassword, sensitiveData, inPublic, PCRSelection{}, nil /*OutsideInfo*/)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -1746,35 +1753,17 @@ func encodeCertifyEx(objectAuth, signerAuth string, object, signer tpmutil.Handl

func decodeCertify(resp []byte) ([]byte, []byte, error) {
var paramSize uint32
var attest, signature tpmutil.U16Bytes
var sigAlg, hashAlg Algorithm
var attest tpmutil.U16Bytes

buf := bytes.NewBuffer(resp)
if err := tpmutil.UnpackBuf(buf, &paramSize); err != nil {
return nil, nil, err
}
buf.Truncate(int(paramSize))
if err := tpmutil.UnpackBuf(buf, &attest, &sigAlg); err != nil {
if err := tpmutil.UnpackBuf(buf, &attest); err != nil {
chrisfenner marked this conversation as resolved.
Show resolved Hide resolved
return nil, nil, err
}
// If sigAlg is AlgNull, there will be no hashAlg or signature.
// This will happen if AlgNull was passed in the Certify() as
// the signing key (no need to sign the response).
// See TPM2 spec part4 pg227 SignAttestInfo()
if sigAlg != AlgNull {
if sigAlg == AlgECDSA {
var r, s tpmutil.U16Bytes
if err := tpmutil.UnpackBuf(buf, &hashAlg, &r, &s); err != nil {
return nil, nil, err
}
signature = append(r, s...)
} else {
if err := tpmutil.UnpackBuf(buf, &hashAlg, &signature); err != nil {
return nil, nil, err
}
}
}
return attest, signature, nil
return attest, buf.Bytes(), nil
}

// Certify generates a signature of a loaded TPM object with a signing key
Expand Down
Loading