Repository: google/go-tpm
Pull request #140 (2019-10-01 09:39:15)

TPM 1.2: GetNVIndex to get information about a given NVIndex
Add GetNVIndex-Function to read attributes of given NVIndex
Add TestGetNVIndex to test it
Add structures, constants and pretty print functions

ChriMarMe: Would be nice to get some feedback today. I'm implementing NVDefineSpace and WriteValue so for the tests I need that function.

Patch:
diff --git a/tpm/constants.go b/tpm/constants.go
index e28fdec..93d0e43 100644
--- a/tpm/constants.go
+++ b/tpm/constants.go
@@ -14,7 +14,11 @@
 
 package tpm
 
-import "github.com/google/go-tpm/tpmutil"
+import (
+	"fmt"
+	"github.com/google/go-tpm/tpmutil"
+	"strings"
+)
 
 // Supported TPM commands.
 const (
@@ -62,6 +66,7 @@ const (
 	capProperty uint32 = 0x00000005
 	capFlag     uint32 = 0x00000004
 	capNVList   uint32 = 0x0000000D
+	capNVIndex  uint32 = 0x00000011
 	capHandle   uint32 = 0x00000014
 )
 
@@ -71,6 +76,63 @@ const (
 	tpmCapFlagPermanent    uint32 = 0x00000108
 )
 
+// permission type
+type permission uint32
+
+// NV Permissions and Operations
+// Note: Permissions are summable
+const (
+	nvPerPPWrite    permission = 0x00000001
+	nvPerOwnerWrite permission = 0x00000002
+	nvPerAuthWrite  permission = 0x00000004
+	nvPerWriteAll   permission = 0x00000800
+	// Warning: The Value 0x00001000 is
+	// defined in the spec as
+	// TPM_NV_PER_WRITEDEFINE, but it is
+	// not included directly in this
+	// code because it locks the given
+	// NV Index permanently if used
+	// incorrectly. This operation can't
+	// be undone in any way. Do not use
+	// this value unless you know what
+	// you're doing!
+	nvPerWriteSTClear permission = 0x00002000
+	nvPerGlobalLock   permission = 0x00004000
+	nvPerPPRead       permission = 0x00008000
+	nvPerOwnerRead    permission = 0x00100000
+	nvPerAuthRead     permission = 0x00200000
+	nvPerReadSTClear  permission = 0x80000000
+)
+
+// permMap : Map of TPM_NV_Permissions to its strings for convenience
+var permMap = map[permission]string{
+	nvPerPPWrite:      "PPWrite",
+	nvPerOwnerWrite:   "OwnerWrite",
+	nvPerAuthWrite:    "AuthWrite",
+	nvPerWriteAll:     "WriteAll",
+	nvPerWriteSTClear: " WriteSTClear",
+	nvPerGlobalLock:   "GlobalLock",
+	nvPerPPRead:       "PPRead",
+	nvPerOwnerRead:    "OwnerRead",
+	nvPerAuthRead:     "AuthRead",
+	nvPerReadSTClear:  "ReadSTClear",
+}
+
+// String returns a textual representation of the set of permissions
+func (p permission) String() string {
+	var retString strings.Builder
+	for iterator, item := range permMap {
+		if (p & iterator) != 0 {
+			retString.WriteString(item + " + ")
+		}
+	}
+	if retString.String() == "" {
+		return "Permission/s not found"
+	}
+	return strings.TrimSuffix(retString.String(), " + ")
+
+}
+
 // Entity types. The LSB gives the entity type, and the MSB (currently fixed to
 // 0x00) gives the ADIP type. ADIP type 0x00 is XOR.
 const (
@@ -92,6 +154,42 @@ const (
 	rtTrans
 )
 
+// Locality type
+type Locality byte
+
+// Values of locality
+// Note: Localities are summable
+const (
+	locZero Locality = 1 << iota
+	locOne
+	locTwo
+	locThree
+	locFour
+)
+
+// LocaMap maps Locality values to strings for convenience
+var locaMap = map[Locality]string{
+	locZero:  "Locality 0",
+	locOne:   "Locality 1",
+	locTwo:   "Locality 2",
+	locThree: "Locality 3",
+	locFour:  "Locality 4",
+}
+
+// PrettyPrint for Localities
+func (l Locality) String() string {
+	var retString strings.Builder
+	for iterator, item := range locaMap {
+		if l&iterator != 0 {
+			retString.WriteString(item + " + ")
+		}
+	}
+	if retString.String() == "" {
+		return fmt.Sprintf("locality %d", int(l))
+	}
+	return strings.TrimSuffix(retString.String(), " + ")
+}
+
 // Entity values.
 const (
 	khSRK         tpmutil.Handle = 0x40000000
diff --git a/tpm/structures.go b/tpm/structures.go
index 9cc8285..f88ddee 100644
--- a/tpm/structures.go
+++ b/tpm/structures.go
@@ -109,6 +109,27 @@ type PermanentFlags struct {
 	DisableFullDALogicInfo       bool
 }
 
+// NVDataPublic implements the structure of TPM_NV_DATA_PUBLIC
+// as described in TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011, P. 142
+type NVDataPublic struct {
+	Tag          tpmutil.Tag
+	NVIndex      uint32
+	PCRInfoRead  pcrInfoShort
+	PCRInfoWrite pcrInfoShort
+	permission   NVAttributes
+	ReadSTClear  bool
+	WriteSTClear bool
+	WriteDefine  bool
+	Size         uint32
+}
+
+// NVAttributes implements struct of TPM_NV_ATTRIBUTES
+// See: TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011, P.140
+type NVAttributes struct {
+	tag        tpmutil.Tag
+	attributes permission
+}
+
 // CloseKey flushes the key associated with the tpmutil.Handle.
 func CloseKey(rw io.ReadWriter, h tpmutil.Handle) error {
 	return flushSpecific(rw, h, rtKey)
diff --git a/tpm/tpm.go b/tpm/tpm.go
index fc06a62..48b4087 100644
--- a/tpm/tpm.go
+++ b/tpm/tpm.go
@@ -1028,6 +1028,23 @@ func GetNVList(rw io.ReadWriter) ([]uint32, error) {
 	return nvList, err
 }
 
+// GetNVIndex returns the structure of nvDataPublic which contains
+// information about the requested NV Index.
+// See: TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011, P.167
+func GetNVIndex(rw io.ReadWriter, nvIndex uint32) (NVDataPublic, error) {
+	var nvInfo NVDataPublic
+	buf, err := getCapability(rw, capNVIndex, 0)
+	if err != nil {
+		return nvInfo, fmt.Errorf("failed to get capability NVIndex: %v", err)
+	}
+	r := bytes.NewReader(buf)
+	err = binary.Read(r, binary.LittleEndian, &nvInfo)
+	if err != nil {
+		return nvInfo, fmt.Errorf("failed to read nvInfo: %v", err)
+	}
+	return nvInfo, nil
+}
+
 // OwnerClear uses owner auth to clear the TPM. After this operation, the TPM
 // can change ownership.
 func OwnerClear(rw io.ReadWriter, ownerAuth digest) error {


Test patch:
diff --git a/tpm/tpm_test.go b/tpm/tpm_test.go
index 87136c7..5de7c02 100644
--- a/tpm/tpm_test.go
+++ b/tpm/tpm_test.go
@@ -101,6 +101,25 @@ func TestGetNVList(t *testing.T) {
 	t.Logf("NVList is: %v", nvList)
 }
 
+func TestGetNVIndex(t *testing.T) {
+	rwc := openTPMOrSkip(t)
+	defer rwc.Close()
+
+	nvList, err := GetNVList(rwc)
+	if err != nil {
+		t.Fatalf("Couldn't read NVList %v", err)
+	}
+	var nvInfo []NVDataPublic
+	for _, nvEntry := range nvList {
+		index, err := GetNVIndex(rwc, nvEntry)
+		if err != nil {
+			t.Fatalf("Can't read NVDataPublic of index: %v with: %v", nvEntry, err)
+		}
+		nvInfo = append(nvInfo, index)
+	}
+	t.Logf("NVIndices with Attributes:%v", nvInfo)
+}
+
 func TestPcrExtend(t *testing.T) {
 	rwc := openTPMOrSkip(t)
 	defer rwc.Close()