Repository: google/go-tpm
Pull request #235 (2021-02-25 15:02:20)

Various fixes for Remote Attestation implementations
Summary:

* Fix the wrong usage of signature decoding by using DecodeSignature function (Remote Attestation)
* Fix decodeCertify for wrong signature decoding
* Make EncodeCreationData public
* Introduce OutsideInfo to key creation for key labels
* Improve tpmutil runner with retries to stabilize virtualized TPMs usage

google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-tpm%2Fpull%2F235) for more info**.

<!-- need_author_cla -->

Patch:
diff --git a/tpm2/structures.go b/tpm2/structures.go
index 4040a23..3c863e8 100644
--- a/tpm2/structures.go
+++ b/tpm2/structures.go
@@ -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
@@ -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)
@@ -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
@@ -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) {
 	sel, err := encodeTPMLPCRSelection(cd.PCRSelection)
 	if err != nil {
 		return nil, fmt.Errorf("encoding PCRSelection: %v", err)
diff --git a/tpm2/tpm2.go b/tpm2/tpm2.go
index 08b8a55..7a1c068 100644
--- a/tpm2/tpm2.go
+++ b/tpm2/tpm2.go
@@ -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
@@ -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
 	}
@@ -412,7 +412,7 @@ func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, owne
 		encodedAuth,
 		inSensitive,
 		publicBlob,
-		outsideInfo,
+		outsideInfoBlob,
 		creationPCR,
 	)
 }
@@ -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
 	}
@@ -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
 	}
@@ -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
@@ -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
 	}
@@ -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 {
 		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
diff --git a/tpmutil/run.go b/tpmutil/run.go
index 21a9c66..e14270a 100644
--- a/tpmutil/run.go
+++ b/tpmutil/run.go
@@ -19,6 +19,7 @@ import (
 	"errors"
 	"io"
 	"os"
+	"time"
 )
 
 // maxTPMResponse is the largest possible response from the TPM. We need to know
@@ -41,32 +42,51 @@ func RunCommand(rw io.ReadWriter, tag Tag, cmd Command, in ...interface{}) ([]by
 		return nil, 0, err
 	}
 
-	if _, err := rw.Write(inb); err != nil {
-		return nil, 0, err
-	}
+	// f(t) = (2^t)ms, up to 2s
+	var backoffFac uint = 0
+	var rh responseHeader
+	var outb []byte
 
-	// If the TPM is a real device, it may not be ready for reading immediately after writing
-	// the command. Wait until the file descriptor is ready to be read from.
-	if f, ok := rw.(*os.File); ok {
-		if err = poll(f); err != nil {
+	for {
+		if _, err := rw.Write(inb); err != nil {
 			return nil, 0, err
 		}
-	}
 
-	outb := make([]byte, maxTPMResponse)
-	outlen, err := rw.Read(outb)
-	if err != nil {
-		return nil, 0, err
-	}
-	// Resize the buffer to match the amount read from the TPM.
-	outb = outb[:outlen]
+		// If the TPM is a real device, it may not be ready for reading immediately after writing
+		// the command. Wait until the file descriptor is ready to be read from.
+		if f, ok := rw.(*os.File); ok {
+			if err = poll(f); err != nil {
+				return nil, 0, err
+			}
+		}
 
-	var rh responseHeader
-	read, err := Unpack(outb, &rh)
-	if err != nil {
-		return nil, 0, err
+		outb = make([]byte, maxTPMResponse)
+		outlen, err := rw.Read(outb)
+		if err != nil {
+			return nil, 0, err
+		}
+		// Resize the buffer to match the amount read from the TPM.
+		outb = outb[:outlen]
+
+		read, err := Unpack(outb, &rh)
+		if err != nil {
+			return nil, 0, err
+		}
+		outb = outb[read:]
+
+		// In case TPM is busy retry the command after waiting a few miliseconds
+		if rh.Res == RCRetry {
+			if backoffFac < 11 {
+				dur := (1 << backoffFac) * time.Millisecond
+				time.Sleep(dur)
+				backoffFac++
+			} else {
+				return nil, 0, err
+			}
+		} else {
+			break
+		}
 	}
-	outb = outb[read:]
 
 	if rh.Res != RCSuccess {
 		return nil, rh.Res, nil
diff --git a/tpmutil/structures.go b/tpmutil/structures.go
index d7d05fb..c945535 100644
--- a/tpmutil/structures.go
+++ b/tpmutil/structures.go
@@ -145,6 +145,9 @@ type ResponseCode uint32
 // 2.0.
 const RCSuccess ResponseCode = 0x000
 
+// RCRetry is response code for TPM is busy.
+const RCRetry ResponseCode = 0x922
+
 // A responseHeader is a header for TPM responses.
 type responseHeader struct {
 	Tag  Tag


Test patch:
diff --git a/tpm2/encoding_test.go b/tpm2/encoding_test.go
index 4462e4e..1f79fb1 100644
--- a/tpm2/encoding_test.go
+++ b/tpm2/encoding_test.go
@@ -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)
 	}
@@ -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)
 	}
@@ -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)
 	}
diff --git a/tpm2/test/tpm2_test.go b/tpm2/test/tpm2_test.go
index 208e684..14ab0d6 100644
--- a/tpm2/test/tpm2_test.go
+++ b/tpm2/test/tpm2_test.go
@@ -27,7 +27,6 @@ import (
 	"fmt"
 	"hash"
 	"io"
-	"math/big"
 	"reflect"
 	"strings"
 	"testing"
@@ -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)
 	}
 
@@ -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)
 		}
 	}
@@ -1227,7 +1236,7 @@ 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)
 	}
@@ -1235,6 +1244,11 @@ func TestCreateAndCertifyCreation(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)
 	}
@@ -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)
 	}
 }
@@ -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)
 	}
@@ -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)
 	}
@@ -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")
 	}
 }