Repository: google/go-tpm
Pull request #195 (2020-07-23 18:11:22)

Fix TPM 1.2 migration
Fix some TPM 1.2-specific issues related to key migration and testing, along with CVE-2020-8918:

- A bug in CreateWrapKey that uses an incorrect key to encrypt a key's `migrationAuth` value
- Addition of `AuthorizeMigrationKey` and `CreateMigrationBlob` command functions to enable testing of migration auth bug fix
- A bug fix in TakeOwnership that prevented successful authorization of the command
- A session leak in a couple of TPM 1.2 tests (`TestOIAP` and `TestOSAP`)
- Improvements to the TPM 1.2 tests to allow execution on a TPM that needs to be started up
- Initial effort at documentation for running the TPM 1.2 tests against the IBM simulator


Patch:
diff --git a/tpm/commands.go b/tpm/commands.go
index 43b22d9..a8c8767 100644
--- a/tpm/commands.go
+++ b/tpm/commands.go
@@ -103,6 +103,40 @@ func unseal(rw io.ReadWriter, keyHandle tpmutil.Handle, sealed *tpmStoredData, c
 	return outb, &ra1, &ra2, ret, nil
 }
 
+// authorizeMigrationKey authorizes a public key for migrations.
+func authorizeMigrationKey(rw io.ReadWriter, migrationScheme MigrationScheme, migrationKey pubKey, ca *commandAuth) ([]byte, *responseAuth, uint32, error) {
+	in := []interface{}{migrationScheme, migrationKey, ca}
+	var ra responseAuth
+	var migrationAuth migrationKeyAuth
+	out := []interface{}{&migrationAuth, &ra}
+	ret, err := submitTPMRequest(rw, tagRQUAuth1Command, ordAuthorizeMigrationKey, in, out)
+	if err != nil {
+		return nil, nil, 0, err
+	}
+	authBlob, err := tpmutil.Pack(migrationAuth)
+	if err != nil {
+		return nil, nil, 0, err
+	}
+
+	return authBlob, &ra, ret, nil
+}
+
+// createMigrationBlob migrates a key from the TPM.
+func createMigrationBlob(rw io.ReadWriter, parentHandle tpmutil.Handle, migrationScheme MigrationScheme, migrationKey []byte, encData tpmutil.U32Bytes, ca1 *commandAuth, ca2 *commandAuth) ([]byte, []byte, *responseAuth, *responseAuth, uint32, error) {
+	in := []interface{}{parentHandle, migrationScheme, migrationKey, encData, ca1, ca2}
+	var rand tpmutil.U32Bytes
+	var outData tpmutil.U32Bytes
+	var ra1 responseAuth
+	var ra2 responseAuth
+	out := []interface{}{&rand, &outData, &ra1, &ra2}
+	ret, err := submitTPMRequest(rw, tagRQUAuth2Command, ordCreateMigrationBlob, in, out)
+	if err != nil {
+		return nil, nil, nil, nil, 0, err
+	}
+
+	return rand, outData, &ra1, &ra2, ret, nil
+}
+
 // flushSpecific removes a handle from the TPM. Note that removing a handle
 // doesn't require any authentication.
 func flushSpecific(rw io.ReadWriter, handle tpmutil.Handle, resourceType uint32) error {
diff --git a/tpm/constants.go b/tpm/constants.go
index 3e2452d..39cf40c 100644
--- a/tpm/constants.go
+++ b/tpm/constants.go
@@ -36,35 +36,39 @@ const (
 
 // Supported TPM operations.
 const (
-	ordOIAP                 uint32 = 0x0000000A
-	ordOSAP                 uint32 = 0x0000000B
-	ordTakeOwnership        uint32 = 0x0000000D
-	ordExtend               uint32 = 0x00000014
-	ordPCRRead              uint32 = 0x00000015
-	ordQuote                uint32 = 0x00000016
-	ordSeal                 uint32 = 0x00000017
-	ordUnseal               uint32 = 0x00000018
-	ordCreateWrapKey        uint32 = 0x0000001F
-	ordGetPubKey            uint32 = 0x00000021
-	ordSign                 uint32 = 0x0000003C
-	ordQuote2               uint32 = 0x0000003E
-	ordResetLockValue       uint32 = 0x00000040
-	ordLoadKey2             uint32 = 0x00000041
-	ordGetRandom            uint32 = 0x00000046
-	ordOwnerClear           uint32 = 0x0000005B
-	ordForceClear           uint32 = 0x0000005D
-	ordGetCapability        uint32 = 0x00000065
-	ordMakeIdentity         uint32 = 0x00000079
-	ordActivateIdentity     uint32 = 0x0000007A
-	ordReadPubEK            uint32 = 0x0000007C
-	ordOwnerReadInternalPub uint32 = 0x00000081
-	ordFlushSpecific        uint32 = 0x000000BA
-	ordNVDefineSpace        uint32 = 0x000000CC
-	ordPcrReset             uint32 = 0x000000C8
-	ordNVWriteValue         uint32 = 0x000000CD
-	ordNVWriteValueAuth     uint32 = 0x000000CE
-	ordNVReadValue          uint32 = 0x000000CF
-	ordNVReadValueAuth      uint32 = 0x000000D0
+	ordOIAP                     uint32 = 0x0000000A
+	ordOSAP                     uint32 = 0x0000000B
+	ordTakeOwnership            uint32 = 0x0000000D
+	ordExtend                   uint32 = 0x00000014
+	ordPCRRead                  uint32 = 0x00000015
+	ordQuote                    uint32 = 0x00000016
+	ordSeal                     uint32 = 0x00000017
+	ordUnseal                   uint32 = 0x00000018
+	ordCreateWrapKey            uint32 = 0x0000001F
+	ordGetPubKey                uint32 = 0x00000021
+	ordCreateMigrationBlob      uint32 = 0x00000028
+	ordAuthorizeMigrationKey    uint32 = 0x0000002b
+	ordSign                     uint32 = 0x0000003C
+	ordQuote2                   uint32 = 0x0000003E
+	ordResetLockValue           uint32 = 0x00000040
+	ordLoadKey2                 uint32 = 0x00000041
+	ordGetRandom                uint32 = 0x00000046
+	ordOwnerClear               uint32 = 0x0000005B
+	ordForceClear               uint32 = 0x0000005D
+	ordGetCapability            uint32 = 0x00000065
+	ordCreateEndorsementKeyPair uint32 = 0x00000078
+	ordMakeIdentity             uint32 = 0x00000079
+	ordActivateIdentity         uint32 = 0x0000007A
+	ordReadPubEK                uint32 = 0x0000007C
+	ordOwnerReadInternalPub     uint32 = 0x00000081
+	ordStartup                  uint32 = 0x00000099
+	ordFlushSpecific            uint32 = 0x000000BA
+	ordNVDefineSpace            uint32 = 0x000000CC
+	ordPcrReset                 uint32 = 0x000000C8
+	ordNVWriteValue             uint32 = 0x000000CD
+	ordNVWriteValueAuth         uint32 = 0x000000CE
+	ordNVReadValue              uint32 = 0x000000CF
+	ordNVReadValueAuth          uint32 = 0x000000D0
 )
 
 // Capability types.
@@ -294,6 +298,28 @@ const (
 	authPrivUseOnly byte = 0x03
 )
 
+// KeyFlags represents TPM_KEY_FLAGS.
+type KeyFlags uint32
+
+const (
+	keyRedirection      KeyFlags = 0x00000001
+	keyMigratable       KeyFlags = 0x00000002
+	keyIsVolatile       KeyFlags = 0x00000004
+	keyPcrIgnoredOnRead KeyFlags = 0x00000008
+	keyMigrateAuthority KeyFlags = 0x00000010
+)
+
+// MigrationScheme represents TPM_MIGRATE_SCHEME.
+type MigrationScheme uint16
+
+const (
+	msMigrate         MigrationScheme = 0x0001
+	msRewrap          MigrationScheme = 0x0002
+	msMaint           MigrationScheme = 0x0003
+	msRestrictMigrate MigrationScheme = 0x0004
+	msRestrictApprove MigrationScheme = 0x0005
+)
+
 // fixedQuote is the fixed constant string used in quoteInfo.
 var fixedQuote = [4]byte{byte('Q'), byte('U'), byte('O'), byte('T')}
 
diff --git a/tpm/open_other.go b/tpm/open_other.go
index e39558b..0925da9 100644
--- a/tpm/open_other.go
+++ b/tpm/open_other.go
@@ -27,6 +27,12 @@ import (
 // device, then it treats it like a normal TPM device, and if the file is a
 // Unix domain socket, then it opens a connection to the socket.
 func OpenTPM(path string) (io.ReadWriteCloser, error) {
+	return openAndStartupTPM(path, false)
+}
+
+// openAndStartupTPM opens the TPM and optionally runs TPM_Startup if needed.
+// This feature is implemented only for testing.
+func openAndStartupTPM(path string, doStartup bool) (io.ReadWriteCloser, error) {
 	rwc, err := tpmutil.OpenTPM(path)
 	if err != nil {
 		return nil, err
@@ -34,9 +40,14 @@ func OpenTPM(path string) (io.ReadWriteCloser, error) {
 
 	// Make sure this is a TPM 1.2
 	_, err = GetManufacturer(rwc)
+	if doStartup && err == tpmError(errInvalidPostInit) {
+		if err = startup(rwc); err == nil {
+			_, err = GetManufacturer(rwc)
+		}
+	}
 	if err != nil {
 		rwc.Close()
-		return nil, fmt.Errorf("open %s: device is not a TPM 1.2", path)
+		return nil, fmt.Errorf("open %s: device is not a TPM 1.2: %v", path, err)
 	}
 	return rwc, nil
 }
diff --git a/tpm/structures.go b/tpm/structures.go
index 0e5b6ad..f59436f 100644
--- a/tpm/structures.go
+++ b/tpm/structures.go
@@ -256,7 +256,7 @@ type symmetricKeyParams struct {
 type key struct {
 	Version         uint32
 	KeyUsage        uint16
-	KeyFlags        uint32
+	KeyFlags        KeyFlags
 	AuthDataUsage   byte
 	AlgorithmParams keyParams
 	PCRInfo         tpmutil.U32Bytes
@@ -283,6 +283,13 @@ type pubKey struct {
 	Key             tpmutil.U32Bytes
 }
 
+// A migrationKeyAuth represents the target of a migration.
+type migrationKeyAuth struct {
+	MigrationKey    pubKey
+	MigrationScheme MigrationScheme
+	Digest          Digest
+}
+
 // A symKey is a TPM representation of a symmetric key.
 type symKey struct {
 	AlgID     Algorithm
diff --git a/tpm/tpm.go b/tpm/tpm.go
index 60c5db8..9f54ef4 100644
--- a/tpm/tpm.go
+++ b/tpm/tpm.go
@@ -121,7 +121,7 @@ func LoadKey2(rw io.ReadWriter, keyBlob []byte, srkAuth []byte) (tpmutil.Handle,
 	defer zeroBytes(sharedSecret[:])
 
 	authIn := []interface{}{ordLoadKey2, k}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return 0, err
 	}
@@ -160,7 +160,7 @@ func Quote2(rw io.ReadWriter, handle tpmutil.Handle, data []byte, pcrVals []int,
 		return nil, err
 	}
 	authIn := []interface{}{ordQuote2, hash, pcrSel, addVersion}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -193,7 +193,7 @@ func GetPubKey(rw io.ReadWriter, keyHandle tpmutil.Handle, srkAuth []byte) ([]by
 	defer zeroBytes(sharedSecret[:])
 
 	authIn := []interface{}{ordGetPubKey}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -256,18 +256,29 @@ func newOSAPSession(rw io.ReadWriter, entityType uint16, entityValue tpmutil.Han
 }
 
 // newCommandAuth creates a new commandAuth structure over the given
-// parameters, using the given secret for HMAC computation.
-func newCommandAuth(authHandle tpmutil.Handle, nonceEven Nonce, key []byte, params []interface{}) (*commandAuth, error) {
+// parameters, using the given secret and the given odd nonce, if provided,
+// for the HMAC. If no odd nonce is provided, one is randomly generated.
+func newCommandAuth(authHandle tpmutil.Handle, nonceEven Nonce, nonceOdd *Nonce, key []byte, params []interface{}) (*commandAuth, error) {
 	// Auth = HMAC-SHA1(key, SHA1(params) || NonceEven || NonceOdd || ContSession)
 	digestBytes, err := tpmutil.Pack(params...)
 	if err != nil {
 		return nil, err
 	}
-
 	digest := sha1.Sum(digestBytes)
-	ca := &commandAuth{AuthHandle: authHandle}
-	if _, err := rand.Read(ca.NonceOdd[:]); err != nil {
-		return nil, err
+
+	// Use the passed-in nonce if non-nil, otherwise generate it now.
+	var odd Nonce
+	if nonceOdd != nil {
+		odd = *nonceOdd
+	} else {
+		if _, err := rand.Read(odd[:]); err != nil {
+			return nil, err
+		}
+	}
+
+	ca := &commandAuth{
+		AuthHandle: authHandle,
+		NonceOdd:   odd,
 	}
 
 	authBytes, err := tpmutil.Pack(digest, nonceEven, ca.NonceOdd, ca.ContSession)
@@ -349,7 +360,7 @@ func sealHelper(rw io.ReadWriter, pcrInfo *pcrInfoLong, data []byte, srkAuth []b
 	//               len(data) || data)
 	//
 	authIn := []interface{}{ordSeal, sc.EncAuth, uint32(binary.Size(pcrInfo)), pcrInfo, tpmutil.U32Bytes(data)}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -423,14 +434,14 @@ func Unseal(rw io.ReadWriter, sealed []byte, srkAuth []byte) ([]byte, error) {
 	authIn := []interface{}{ordUnseal, tsd}
 
 	// The first commandAuth uses the shared secret as an HMAC key.
-	ca1, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca1, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
 	}
 
 	// The second commandAuth is based on OIAP instead of OSAP and uses the
 	// SRK auth value as an HMAC key instead of the shared secret.
-	ca2, err := newCommandAuth(oiapr.AuthHandle, oiapr.NonceEven, srkAuth, authIn)
+	ca2, err := newCommandAuth(oiapr.AuthHandle, oiapr.NonceEven, nil, srkAuth, authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -472,7 +483,7 @@ func Quote(rw io.ReadWriter, handle tpmutil.Handle, data []byte, pcrNums []int,
 		return nil, nil, err
 	}
 	authIn := []interface{}{ordQuote, hash, pcrSel}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -586,12 +597,12 @@ func MakeIdentity(rw io.ReadWriter, srkAuth []byte, ownerAuth []byte, aikAuth []
 	// digest = SHA1(ordMakeIdentity || encAuth || caDigest || aik)
 	//
 	authIn := []interface{}{ordMakeIdentity, encAuth, caDigest, aik}
-	ca1, err := newCommandAuth(osaprSRK.AuthHandle, osaprSRK.NonceEven, sharedSecretSRK[:], authIn)
+	ca1, err := newCommandAuth(osaprSRK.AuthHandle, osaprSRK.NonceEven, nil, sharedSecretSRK[:], authIn)
 	if err != nil {
 		return nil, err
 	}
 
-	ca2, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca2, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -675,11 +686,11 @@ func ActivateIdentity(rw io.ReadWriter, aikAuth []byte, ownerAuth []byte, aik tp
 	defer zeroBytes(sharedSecretOwn[:])
 
 	authIn := []interface{}{ordActivateIdentity, tpmutil.U32Bytes(asym)}
-	ca1, err := newCommandAuth(oiaprAIK.AuthHandle, oiaprAIK.NonceEven, aikAuth, authIn)
+	ca1, err := newCommandAuth(oiaprAIK.AuthHandle, oiaprAIK.NonceEven, nil, aikAuth, authIn)
 	if err != nil {
 		return nil, fmt.Errorf("newCommandAuth failed: %v", err)
 	}
-	ca2, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca2, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return nil, fmt.Errorf("newCommandAuth failed: %v", err)
 	}
@@ -757,7 +768,7 @@ func ResetLockValue(rw io.ReadWriter, ownerAuth Digest) error {
 	// digest = SHA1(ordResetLockValue)
 	//
 	authIn := []interface{}{ordResetLockValue}
-	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return err
 	}
@@ -794,7 +805,7 @@ func ownerReadInternalHelper(rw io.ReadWriter, kh tpmutil.Handle, ownerAuth Dige
 	// digest = SHA1(ordOwnerReadInternalPub || kh)
 	//
 	authIn := []interface{}{ordOwnerReadInternalPub, kh}
-	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -929,7 +940,7 @@ func NVDefineSpace(rw io.ReadWriter, nvData NVDataPublic, ownAuth []byte) error
 		encAuthData := sha1.Sum(xorData)
 
 		authIn := []interface{}{ordNVDefineSpace, nvData, encAuthData}
-		ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+		ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 		if err != nil {
 			return err
 		}
@@ -965,7 +976,7 @@ func NVReadValue(rw io.ReadWriter, index, offset, len uint32, ownAuth []byte) ([
 	defer osaprOwn.Close(rw)
 	defer zeroBytes(sharedSecretOwn[:])
 	authIn := []interface{}{ordNVReadValue, index, offset, len}
-	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return nil, fmt.Errorf("failed to construct owner auth fields: %v", err)
 	}
@@ -996,7 +1007,7 @@ func NVReadValueAuth(rw io.ReadWriter, index, offset, len uint32, auth []byte) (
 	defer osapr.Close(rw)
 	defer zeroBytes(sharedSecret[:])
 	authIn := []interface{}{ordNVReadValueAuth, index, offset, len}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, fmt.Errorf("failed to construct auth fields: %v", err)
 	}
@@ -1028,7 +1039,7 @@ func NVWriteValue(rw io.ReadWriter, index, offset uint32, data []byte, ownAuth [
 	defer osaprOwn.Close(rw)
 	defer zeroBytes(sharedSecretOwn[:])
 	authIn := []interface{}{ordNVWriteValue, index, offset, len(data), data}
-	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return fmt.Errorf("failed to construct owner auth fields: %v", err)
 	}
@@ -1059,7 +1070,7 @@ func NVWriteValueAuth(rw io.ReadWriter, index, offset uint32, data []byte, auth
 	defer osapr.Close(rw)
 	defer zeroBytes(sharedSecret[:])
 	authIn := []interface{}{ordNVWriteValueAuth, index, offset, len(data), data}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return fmt.Errorf("failed to construct auth fields: %v", err)
 	}
@@ -1200,7 +1211,7 @@ func OwnerClear(rw io.ReadWriter, ownerAuth Digest) error {
 	// digest = SHA1(ordOwnerClear)
 	//
 	authIn := []interface{}{ordOwnerClear}
-	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, sharedSecretOwn[:], authIn)
+	ca, err := newCommandAuth(osaprOwn.AuthHandle, osaprOwn.NonceEven, nil, sharedSecretOwn[:], authIn)
 	if err != nil {
 		return err
 	}
@@ -1279,8 +1290,8 @@ func TakeOwnership(rw io.ReadWriter, newOwnerAuth Digest, newSRKAuth Digest, pub
 	// The digest for TakeOwnership is
 	//
 	// SHA1(ordTakeOwnership || pidOwner || encOwnerAuth || encSRKAuth || srk)
-	authIn := []interface{}{ordTakeOwnership, pidOwner, encOwnerAuth, encSRKAuth, srk}
-	ca, err := newCommandAuth(oiapr.AuthHandle, oiapr.NonceEven, newOwnerAuth[:], authIn)
+	authIn := []interface{}{ordTakeOwnership, pidOwner, tpmutil.U32Bytes(encOwnerAuth), tpmutil.U32Bytes(encSRKAuth), srk}
+	ca, err := newCommandAuth(oiapr.AuthHandle, oiapr.NonceEven, nil, newOwnerAuth[:], authIn)
 	if err != nil {
 		return err
 	}
@@ -1294,15 +1305,7 @@ func TakeOwnership(rw io.ReadWriter, newOwnerAuth Digest, newSRKAuth Digest, pub
 	return ra.verify(ca.NonceOdd, newOwnerAuth[:], raIn)
 }
 
-// CreateWrapKey creates a new RSA key for signatures inside the TPM. It is
-// wrapped by the SRK (which is to say, the SRK is the parent key). The key can
-// be bound to the specified PCR numbers so that it can only be used for
-// signing if the PCR values of those registers match. The pcrs parameter can
-// be nil in which case the key is not bound to any PCRs. The usageAuth
-// parameter defines the auth key for using this new key. The migrationAuth
-// parameter would be used for authorizing migration of the key (although this
-// code currently disables migration).
-func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migrationAuth Digest, pcrs []int) ([]byte, error) {
+func createWrapKeyHelper(rw io.ReadWriter, srkAuth []byte, keyFlags KeyFlags, usageAuth Digest, migrationAuth Digest, pcrs []int) (*key, error) {
 	// Run OSAP for the SRK, reading a random OddOSAP for our initial
 	// command and getting back a secret and a handle.
 	sharedSecret, osapr, err := newOSAPSession(rw, etSRK, khSRK, srkAuth)
@@ -1317,15 +1320,35 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migration
 		return nil, err
 	}
 	defer zeroBytes(xorData)
+
+	// We have to come up with NonceOdd early to encrypt the migration auth.
+	var nonceOdd Nonce
+	if _, err := rand.Read(nonceOdd[:]); err != nil {
+		return nil, err
+	}
+
+	// ADIP (Authorization Data Insertion Protocol) is based on NonceEven for the first auth value
+	// encrypted by the protocol, and NonceOdd for the second auth value. This is so that the two
+	// keystreams are independent - otherwise, an eavesdropping attacker could XOR the two encrypted
+	// values together to cancel out the key and calculate (usageAuth ^ migrationAuth).
+	xorData2, err := tpmutil.Pack(sharedSecret, nonceOdd)
+	if err != nil {
+		return nil, err
+	}
+	defer zeroBytes(xorData2)
+
 	encAuthDataKey := sha1.Sum(xorData)
+	defer zeroBytes(encAuthDataKey[:])
+	encAuthDataKey2 := sha1.Sum(xorData2)
+	defer zeroBytes(encAuthDataKey2[:])
 
 	var encUsageAuth Digest
-	for i := range srkAuth {
+	for i := range usageAuth {
 		encUsageAuth[i] = encAuthDataKey[i] ^ usageAuth[i]
 	}
 	var encMigrationAuth Digest
-	for i := range srkAuth {
-		encMigrationAuth[i] = encAuthDataKey[i] ^ migrationAuth[i]
+	for i := range migrationAuth {
+		encMigrationAuth[i] = encAuthDataKey2[i] ^ migrationAuth[i]
 	}
 
 	rParams := rsaKeyParams{
@@ -1352,7 +1375,7 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migration
 	keyInfo := &key{
 		Version:       0x01010000,
 		KeyUsage:      keySigning,
-		KeyFlags:      0,
+		KeyFlags:      keyFlags,
 		AuthDataUsage: authAlways,
 		AlgorithmParams: keyParams{
 			AlgID:     AlgRSA,
@@ -1364,7 +1387,7 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migration
 	}
 
 	authIn := []interface{}{ordCreateWrapKey, encUsageAuth, encMigrationAuth, keyInfo}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, &nonceOdd, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -1379,6 +1402,22 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migration
 		return nil, err
 	}
 
+	return k, nil
+}
+
+// CreateWrapKey creates a new RSA key for signatures inside the TPM. It is
+// wrapped by the SRK (which is to say, the SRK is the parent key). The key can
+// be bound to the specified PCR numbers so that it can only be used for
+// signing if the PCR values of those registers match. The pcrs parameter can
+// be nil in which case the key is not bound to any PCRs. The usageAuth
+// parameter defines the auth key for using this new key. The migrationAuth
+// parameter would be used for authorizing migration of the key (although this
+// code currently disables migration).
+func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migrationAuth Digest, pcrs []int) ([]byte, error) {
+	k, err := createWrapKeyHelper(rw, srkAuth, 0, usageAuth, migrationAuth, pcrs)
+	if err != nil {
+		return nil, err
+	}
 	keyblob, err := tpmutil.Pack(k)
 	if err != nil {
 		return nil, err
@@ -1386,6 +1425,119 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migration
 	return keyblob, nil
 }
 
+// CreateMigratableWrapKey creates a new RSA key as in CreateWrapKey, but the
+// key is migratable (with the given migration auth).
+// Returns the loadable KeyBlob as well as just the encrypted private part, for
+// migration.
+func CreateMigratableWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migrationAuth Digest, pcrs []int) ([]byte, []byte, error) {
+	k, err := createWrapKeyHelper(rw, srkAuth, keyMigratable, usageAuth, migrationAuth, pcrs)
+	if err != nil {
+		return nil, nil, err
+	}
+	keyblob, err := tpmutil.Pack(k)
+	if err != nil {
+		return nil, nil, err
+	}
+	return keyblob, k.EncData, nil
+}
+
+// AuthorizeMigrationKey authorizes a given public key for use in migrating
+// migratable keys. The scheme is REWRAP.
+func AuthorizeMigrationKey(rw io.ReadWriter, ownerAuth Digest, migrationKey crypto.PublicKey) ([]byte, error) {
+	// Run OSAP for the OwnerAuth, reading a random OddOSAP for our initial
+	// command and getting back a secret and a handle.
+	sharedSecret, osapr, err := newOSAPSession(rw, etOwner, khOwner, ownerAuth[:])
+	if err != nil {
+		return nil, err
+	}
+	defer osapr.Close(rw)
+	defer zeroBytes(sharedSecret[:])
+
+	var pub *pubKey
+	if migrationKey != nil {
+		pub, err = convertPubKey(migrationKey)
+		// convertPubKey is designed for signing keys.
+		pub.AlgorithmParams.EncScheme = esRSAEsOAEPSHA1MGF1
+		pub.AlgorithmParams.SigScheme = ssNone
+		rsaParams := rsaKeyParams{
+			KeyLength: 2048,
+			NumPrimes: 2,
+			//Exponent: default (omit)
+		}
+		pub.AlgorithmParams.Params, err = tpmutil.Pack(rsaParams)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	scheme := msRewrap
+
+	// The digest for auth for the authorizeMigrationKey command is computed as
+	// SHA1(ordAuthorizeMigrationkey || migrationScheme || migrationKey)
+	authIn := []interface{}{ordAuthorizeMigrationKey, scheme, pub}
+
+	// The commandAuth uses the shared secret as an HMAC key.
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
+	if err != nil {
+		return nil, err
+	}
+
+	migrationAuth, _, _, err := authorizeMigrationKey(rw, scheme, *pub, ca)
+	if err != nil {
+		return nil, err
+	}
+
+	// For now, ignore the response authentication.
+	return migrationAuth, nil
+}
+
+// CreateMigrationBlob performs a Rewrap migration of the given key blob.
+func CreateMigrationBlob(rw io.ReadWriter, srkAuth Digest, migrationAuth Digest, keyBlob []byte, migrationKeyBlob []byte) ([]byte, error) {
+	// Run OSAP for the SRK, reading a random OddOSAP for our initial
+	// command and getting back a secret and a handle.
+	sharedSecret, osapr, err := newOSAPSession(rw, etSRK, khSRK, srkAuth[:])
+	if err != nil {
+		return nil, err
+	}
+	defer osapr.Close(rw)
+	defer zeroBytes(sharedSecret[:])
+
+	// The createMigrationBlob command needs an OIAP session in addition to the
+	// OSAP session.
+	oiapr, err := oiap(rw)
+	if err != nil {
+		return nil, err
+	}
+	defer oiapr.Close(rw)
+
+	encData := tpmutil.U32Bytes(keyBlob)
+
+	// The digest for auth1 and auth2 for the createMigrationBlob command is
+	// SHA1(ordCreateMigrationBlob || migrationScheme || migrationKeyBlob || encData)
+	authIn := []interface{}{ordCreateMigrationBlob, msRewrap, migrationKeyBlob, encData}
+
+	// The first commandAuth uses the shared secret as an HMAC key.
+	ca1, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
+	if err != nil {
+		return nil, err
+	}
+
+	// The second commandAuth is based on OIAP instead of OSAP and uses the
+	// migration auth as the HMAC key.
+	ca2, err := newCommandAuth(oiapr.AuthHandle, oiapr.NonceEven, nil, migrationAuth[:], authIn)
+	if err != nil {
+		return nil, err
+	}
+
+	_, outData, _, _, _, err := createMigrationBlob(rw, khSRK, msRewrap, migrationKeyBlob, encData, ca1, ca2)
+	if err != nil {
+		return nil, err
+	}
+
+	// For now, ignore the response authenticatino.
+	return outData, nil
+}
+
 // https://golang.org/src/crypto/rsa/pkcs1v15.go?s=8762:8862#L204
 var hashPrefixes = map[crypto.Hash][]byte{
 	crypto.MD5:       {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
@@ -1418,7 +1570,7 @@ func Sign(rw io.ReadWriter, keyAuth []byte, keyHandle tpmutil.Handle, hash crypt
 	defer zeroBytes(sharedSecret[:])
 
 	authIn := []interface{}{ordSign, tpmutil.U32Bytes(data)}
-	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
+	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, nil, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
 	}
@@ -1460,3 +1612,32 @@ func ForceClear(rw io.ReadWriter) error {
 
 	return err
 }
+
+// Startup performs TPM_Startup(TPM_ST_CLEAR) to initialize the TPM.
+func startup(rw io.ReadWriter) error {
+	var typ uint16 = 0x0001 // TPM_ST_CLEAR
+	in := []interface{}{typ}
+	out := []interface{}{}
+	_, err := submitTPMRequest(rw, tagRQUCommand, ordStartup, in, out)
+
+	return err
+}
+
+// createEK performs TPM_CreateEndorsementKeyPair to create the EK in the TPM.
+func createEK(rw io.ReadWriter) error {
+	antiReplay := Nonce{}
+	keyInfo := []byte{
+		0x00, 0x00, 0x00, 0x01, // Algorithm = RSA
+		0x00, 0x03, // EncScheme = OAEP
+		0x00, 0x01, // SigScheme = None
+		0x00, 0x00, 0x00, 0x0c, // ParamsSize = 12
+		0x00, 0x00, 0x08, 0x00, // KeyLength = 2048
+		0x00, 0x00, 0x00, 0x02, // NumPrimes = 2
+		0x00, 0x00, 0x00, 0x00, // ExponentSize = 0 (default 65537 exponent)
+	}
+	in := []interface{}{antiReplay, keyInfo}
+	out := []interface{}{}
+	_, err := submitTPMRequest(rw, tagRQUCommand, ordCreateEndorsementKeyPair, in, out)
+
+	return err
+}


Test patch:
diff --git a/tpm/testing.md b/tpm/testing.md
new file mode 100644
index 0000000..3fc91f9
--- /dev/null
+++ b/tpm/testing.md
@@ -0,0 +1,43 @@
+# Testing TPM 1.2 Functionality
+
+**TODO(https://github.com/google/go-tpm/issues/91):** Support for testing the TPM 1.2 stack against
+a simulator is a work in progress. Today, it requires several manual steps.
+
+## Overview
+
+As TPM 1.2s are phased out of common developer devices, testing changes to the TPM 1.2 stack is
+difficult without special hardware. To support development on the TPM 1.2 stack without special
+hardware, a TPM 1.2 simulator or emulator may be used. This document discusses how to use
+[IBM's TPM 1.2 simulator](http://ibmswtpm.sourceforge.net) (on a Linux or Mac OS device, Windows is
+not yet supported) to run the go-tpm TPM 1.2 tests (in the `go-tpm/tpm/` directory).
+
+## Downloading, building, and using the IBM TPM 1.2 Simulator
+
+* Download the latest release of the
+[IBM TPM 1.2 Simulator](https://sourceforge.net/projects/ibmswtpm/), unpack the tarball, and `cd`
+into it.
+* Add `-DTPM_UNIX_DOMAIN_SOCKET` to `tpm/makefile-en-ac`.
+* Build the simulator with `make -f tpm/makefile-en-ac`
+* Set `TEMP_TPM=/tmp/tpm` or some other suitable temporary location for the TPM state files and Unix
+  domain socket.
+* Start the simulator with `TPM_PATH=${TEMP_TPM} TPM_PORT=${TEMP_TPM}/tpm.sock`
+
+## Running the TPM 1.2 tests against the IBM TPM 1.2 Simulator
+
+* Comment out the line `t.Skip()` in `TestTakeOwnership`. This test normally does not work on
+  physical TPMs, so it is normally disabled.
+* Use `TestTakeOwnership` to take ownership of the simulated TPM with `TPM_PATH=${TEMP_TPM}/tpm.sock
+  go test -v ./tpm/... -run TestTakeOwnership -count=1`
+* Run the full test suite with `TPM_PATH=${TEMP_TPM}/tpm.sock go test -v ./tpm/...`
+
+## Future Improvements
+
+* Add setup logic to the TPM 1.2 tests to take ownership of an unowned TPM under test.
+* Wrap a TPM 1.2 simulator somewhere (possibly in https://github.com/google/go-tpm-tools) and
+  integrate it into test setup for the TPM 1.2 tests.
+* Resolve issues that necessitated the use of `t.Skip()` in current tests.
+  * Either add an informative comment along with a skip when a test fails for an expected reason, or
+    remove the test.
+* Resolve issues with current tests that fail on the simulator (such as `TestGetAlgs`).
+* Automate the use of a simulator in a Continuous Integration environment that is accessible to
+  GitHub.
\ No newline at end of file
diff --git a/tpm/tpm_other_test.go b/tpm/tpm_other_test.go
index 921b0c5..bcbf983 100644
--- a/tpm/tpm_other_test.go
+++ b/tpm/tpm_other_test.go
@@ -29,7 +29,7 @@ func openTPMOrSkip(t *testing.T) io.ReadWriteCloser {
 		tpmPath = "/dev/tpm0"
 	}
 
-	rwc, err := OpenTPM(tpmPath)
+	rwc, err := openAndStartupTPM(tpmPath, true)
 	if err != nil {
 		t.Skipf("Skipping test, since we can't open %s for read/write: %s\n", tpmPath, err)
 	}
diff --git a/tpm/tpm_test.go b/tpm/tpm_test.go
index a2f2d7e..ef4b3c2 100644
--- a/tpm/tpm_test.go
+++ b/tpm/tpm_test.go
@@ -17,6 +17,7 @@ package tpm
 import (
 	"bytes"
 	"crypto/rand"
+	"crypto/rsa"
 	"crypto/sha1"
 	"crypto/x509"
 	"io/ioutil"
@@ -198,7 +199,7 @@ func TestFetchPCRValues(t *testing.T) {
 		t.Fatal("Couldn't create PCR composite")
 	}
 
-	if len(comp) != int(20) {
+	if len(comp) != 20 {
 		t.Fatal("Invalid PCR composite")
 	}
 
@@ -256,10 +257,11 @@ func TestOIAP(t *testing.T) {
 	defer rwc.Close()
 
 	// Get auth info from OIAP.
-	_, err := oiap(rwc)
+	oiapr, err := oiap(rwc)
 	if err != nil {
 		t.Fatal("Couldn't run OIAP:", err)
 	}
+	defer oiapr.Close(rwc)
 }
 
 func TestOSAP(t *testing.T) {
@@ -276,10 +278,11 @@ func TestOSAP(t *testing.T) {
 		t.Fatal("Couldn't get a random odd OSAP nonce")
 	}
 
-	_, err := osap(rwc, osapc)
+	osapr, err := osap(rwc, osapc)
 	if err != nil {
 		t.Fatal("Couldn't run OSAP:", err)
 	}
+	defer osapr.Close(rwc)
 }
 
 func TestResizeableSlice(t *testing.T) {
@@ -612,6 +615,12 @@ func TestTakeOwnership(t *testing.T) {
 
 	// This test assumes that the TPM has been cleared using OwnerClear.
 	pubEK, err := ReadPubEK(rwc)
+	// Create the EK if needed.
+	if err == tpmError(errNoEndorsement) {
+		if err = createEK(rwc); err == nil {
+			pubEK, err = ReadPubEK(rwc)
+		}
+	}
 	if err != nil {
 		t.Fatal("Couldn't read the public endorsement key from the TPM:", err)
 	}
@@ -688,3 +697,48 @@ func TestNVReadValueNoAuth(t *testing.T) {
 		t.Logf("no values to read in nvram")
 	}
 }
+
+func TestKeyMigration(t *testing.T) {
+	rwc := openTPMOrSkip(t)
+	defer rwc.Close()
+	ownerAuth := getAuth(ownerAuthEnvVar)
+	srkAuth := getAuth(srkAuthEnvVar)
+	// Generate some random migration and usage auth values.
+	migrationAuth := Digest{}
+	usageAuth := Digest{}
+	rand.Read(migrationAuth[:])
+	rand.Read(usageAuth[:])
+
+	// First generate our private key we'll use for migration.
+	mk, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		t.Fatalf("error generating migration key: %v", err)
+	}
+
+	// Then get the key endorsed by the TPM for doing migrations.
+	mb, err := AuthorizeMigrationKey(rwc, ownerAuth, mk.Public())
+	if err != nil {
+		t.Fatalf("error authorizing migration key: %v", err)
+	}
+
+	// Create a migratable key in the TPM.
+	_, privkey, err := CreateMigratableWrapKey(
+		rwc,
+		srkAuth[:],
+		usageAuth,
+		migrationAuth,
+		[]int{}, // no PCR's
+	)
+
+	// Migrate the key to the saved migration key.
+	encPriv, err := CreateMigrationBlob(rwc, srkAuth, migrationAuth, privkey, mb)
+	if err != nil {
+		t.Fatalf("Error migrating created key: %v", err)
+	}
+
+	// Decrypt the key. Successful OAEP decryption implies successful migration.
+	_, err = rsa.DecryptOAEP(sha1.New(), nil, mk, encPriv, []byte{0x54, 0x43, 0x50, 0x41} /* 'TCPA', see TPM 1.2 spec */)
+	if err != nil {
+		t.Errorf("Error decrypting migrated key blob: %v", err)
+	}
+}