Skip to content

Commit

Permalink
Add test on ComputeAuthTimeout
Browse files Browse the repository at this point in the history
The Microsoft TPM2 and IBM SW TPM simulator both use an absolute
value method of `expiration = -expiration` in ComputeAuthTimeout.

As abs(Int32Min) cannot be represented
an an int32, this expression evaluates to Int32Min.

See https://github.com/microsoft/ms-tpm-20-ref/blob/b94f9f92c579b723a16be72a69efbbf9c35ce44e/TPMCmd/tpm/src/command/EA/Policy_spt.c#L189

The function goes on to cast expiration to UINT64. This can either
be sign-extended or zero-extended, which is undefined behavior.
If it is sign-extended, this carries the negative bit to create a
large number (9.22 e+18 ms ~ 292471140.58 years).
If it is zero-extended, this results in 2147483648000 ms ~ 68.1 years.
  • Loading branch information
alexmwu committed Apr 7, 2021
1 parent 863f9b6 commit 3a5410f
Showing 1 changed file with 56 additions and 0 deletions.
56 changes: 56 additions & 0 deletions tpm2/test/tpm2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"fmt"
"hash"
"io"
"math"
"math/big"
"reflect"
"strings"
Expand Down Expand Up @@ -1601,6 +1602,61 @@ func testPolicySigned(t *testing.T, rw io.ReadWriter, expiration int32, signerPa
return timeout, tkt
}

func timeoutToUint64(timeout []byte) uint64 {
// The MSFT TPM simulator uses the MSB to indicate
// whether to expire on reset. Strip this out if set.
timeoutUint64 := binary.BigEndian.Uint64(timeout)
expiryBit := uint64(1) << 63
if timeoutUint64&expiryBit != 0 {
timeoutUint64 -= expiryBit
}
return timeoutUint64
}

func authTimeoutWithinExpectedRange(expiration int32, timeout []byte) bool {
// This function expects the policy to not use nonceTpm.
// https://github.com/microsoft/ms-tpm-20-ref/blob/b94f9f92c579b723a16be72a69efbbf9c35ce44e/TPMCmd/tpm/src/command/EA/Policy_spt.c#L195

absExp := uint64(math.Abs(float64(expiration)))
var authTimeout uint64 = timeoutToUint64(timeout)

absExpInMs := absExp * 1000
if authTimeout < absExpInMs || authTimeout >= absExpInMs+1000 {
return false
}
return true
}

func TestComputeAuthTimeoutAbsValue(t *testing.T) {
// This test tests the absolue value function in
// https://github.com/microsoft/ms-tpm-20-ref/blob/b94f9f92c579b723a16be72a69efbbf9c35ce44e/TPMCmd/tpm/src/command/EA/Policy_spt.c#L189.
// ComputeAuthTimeout casts expiration to UINT64. This is undefined
// behavior for a negative number, either sign or zero-extended.
// This only invokes UB when the expiration is int32 min, as the
// abs value function is `expiration = -expiration`.

rw := openTPM(t)
defer rw.Close()

var expiration int32 = math.MinInt32

timeout, _ := testPolicySecret(t, rw, expiration)
if len(timeout) == 0 {
t.Fatal("Expected a non-empty timeout!")
}
if !authTimeoutWithinExpectedRange(expiration, timeout) {
t.Errorf("The timeout %v is not in the expected range for expiration %v!", timeoutToUint64(timeout), expiration)
}

timeout, _ = testPolicySigned(t, rw, expiration, defaultRsaSignerParams)
if len(timeout) == 0 {
t.Fatal("Expected a non-empty timeout!")
}
if !authTimeoutWithinExpectedRange(expiration, timeout) {
t.Errorf("The timeout %v is not in the expected range for expiration %v!", timeoutToUint64(timeout), expiration)
}
}

func TestQuote(t *testing.T) {
rw := openTPM(t)
defer rw.Close()
Expand Down

0 comments on commit 3a5410f

Please sign in to comment.