Repository: google/go-tpm
Pull request #128 (2019-09-12 07:57:47)

TPM1.2: Add functions GetAlgs and GetNVList
Two more functions for TPM1.2 

ChriMarMe: @tmroeder 
Would you be so kind and have a look?
ChriMarMe: Really need some review here please

Patch:
diff --git a/tpm/constants.go b/tpm/constants.go
index c902c10..e28fdec 100644
--- a/tpm/constants.go
+++ b/tpm/constants.go
@@ -58,8 +58,10 @@ const (
 
 // Capability types.
 const (
+	capAlg      uint32 = 0x00000002
 	capProperty uint32 = 0x00000005
 	capFlag     uint32 = 0x00000004
+	capNVList   uint32 = 0x0000000D
 	capHandle   uint32 = 0x00000014
 )
 
@@ -110,23 +112,46 @@ const (
 	pidTransport
 )
 
+// Algorithm type for more convenient handling.
+// see Algorithm ID for possible values.
+type Algorithm uint32
+
 // Algorithm ID values.
 const (
-	_ uint32 = iota
-	algRSA
+	_ Algorithm = iota
+	AlgRSA
 	_ // was DES
 	_ // was 3DES in EDE mode
-	algSHA
-	algHMAC
-	algAES128
-	algMGF1
-	algAES192
-	algAES256
-	algXOR
+	AlgSHA
+	AlgHMAC
+	AlgAES128
+	AlgMGF1
+	AlgAES192
+	AlgAES256
+	AlgXOR
 )
 
+// AlgMap Map of Algorithms to Strings for nicer output and comparisons, etc.
+var AlgMap = map[Algorithm]string{
+	AlgRSA:    "RSA",
+	AlgSHA:    "SHA1",
+	AlgHMAC:   "HMAC",
+	AlgAES128: "AER128",
+	AlgMGF1:   "MFG1",
+	AlgAES192: "AES192",
+	AlgAES256: "AES256",
+}
+
+func (a Algorithm) String() string {
+	n, ok := AlgMap[a]
+	if !ok {
+		return "unknown_algorithm"
+	}
+	return n
+}
+
 // Encryption schemes. The values esNone and the two that contain the string
-// "RSA" are only valid under algRSA. The other two are symmetric encryption
+// "RSA" are only valid under AlgRSA. The other two are symmetric encryption
 // schemes.
 const (
 	_ uint16 = iota
@@ -138,7 +163,7 @@ const (
 	esSymCBCPKCS5 = 0xff // esSymCBCPKCS5 was taken from go-tspi
 )
 
-// Signature schemes. These are only valid under algRSA.
+// Signature schemes. These are only valid under AlgRSA.
 const (
 	_ uint16 = iota
 	ssNone
diff --git a/tpm/structures.go b/tpm/structures.go
index 063c743..9cc8285 100644
--- a/tpm/structures.go
+++ b/tpm/structures.go
@@ -214,7 +214,7 @@ func (ra responseAuth) String() string {
 
 // These are the parameters of a TPM key.
 type keyParams struct {
-	AlgID     uint32
+	AlgID     Algorithm
 	EncScheme uint16
 	SigScheme uint16
 	Params    tpmutil.U32Bytes // Serialized rsaKeyParams or symmetricKeyParams.
@@ -268,7 +268,7 @@ type pubKey struct {
 
 // A symKey is a TPM representation of a symmetric key.
 type symKey struct {
-	AlgID     uint32
+	AlgID     Algorithm
 	EncScheme uint16
 	Key       tpmutil.U16Bytes // TPM_SYMMETRIC_KEY uses a 16-bit header for Key data
 }
@@ -327,7 +327,7 @@ func convertPubKey(pk crypto.PublicKey) (*pubKey, error) {
 		return nil, err
 	}
 	kp := keyParams{
-		AlgID:     algRSA,
+		AlgID:     AlgRSA,
 		EncScheme: esNone,
 		SigScheme: ssRSASaPKCS1v15SHA1,
 		Params:    rsakpb,
diff --git a/tpm/tpm.go b/tpm/tpm.go
index cc50488..fc06a62 100644
--- a/tpm/tpm.go
+++ b/tpm/tpm.go
@@ -567,7 +567,7 @@ func MakeIdentity(rw io.ReadWriter, srkAuth []byte, ownerAuth []byte, aikAuth []
 	}
 
 	aikParams := keyParams{
-		AlgID:     algRSA,
+		AlgID:     AlgRSA,
 		EncScheme: esNone,
 		SigScheme: ssRSASaPKCS1v15SHA1,
 		Params:    packedParams,
@@ -707,7 +707,7 @@ func ActivateIdentity(rw io.ReadWriter, aikAuth []byte, ownerAuth []byte, aik tp
 		secret    []byte
 	)
 	switch id := symkey.AlgID; id {
-	case algAES128:
+	case AlgAES128:
 		block, err = aes.NewCipher(symkey.Key)
 		if err != nil {
 			return nil, fmt.Errorf("aes.NewCipher failed: %v", err)
@@ -999,6 +999,35 @@ func GetPermanentFlags(rw io.ReadWriter) (PermanentFlags, error) {
 	return ret, err
 }
 
+// GetAlgs returns a list of algorithms supported by the TPM device.
+func GetAlgs(rw io.ReadWriter) ([]Algorithm, error) {
+	var algs []Algorithm
+	for i := AlgRSA; i <= AlgXOR; i++ {
+		buf, err := getCapability(rw, capAlg, uint32(i))
+		if err != nil {
+			return nil, err
+		}
+		if uint8(buf[0]) > 0 {
+			algs = append(algs, Algorithm(i))
+		}
+
+	}
+	return algs, nil
+}
+
+// GetNVList returns a list of TPM_NV_INDEX values that
+// are currently allocated NV storage through TPM_NV_DefineSpace.
+func GetNVList(rw io.ReadWriter) ([]uint32, error) {
+	var nvList []uint32
+	buf, err := getCapability(rw, capNVList, 0)
+	if err != nil {
+		return nil, err
+	}
+	r := bytes.NewReader(buf)
+	err = binary.Read(r, binary.LittleEndian, &nvList)
+	return nvList, err
+}
+
 // OwnerClear uses owner auth to clear the TPM. After this operation, the TPM
 // can change ownership.
 func OwnerClear(rw io.ReadWriter, ownerAuth digest) error {
@@ -1072,7 +1101,7 @@ func TakeOwnership(rw io.ReadWriter, newOwnerAuth digest, newSRKAuth digest, pub
 		return err
 	}
 	srkParams := keyParams{
-		AlgID:     algRSA,
+		AlgID:     AlgRSA,
 		EncScheme: esRSAEsOAEPSHA1MGF1,
 		SigScheme: ssNone,
 		Params:    srkpb,
@@ -1171,7 +1200,7 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth digest, migration
 		KeyFlags:      0,
 		AuthDataUsage: authAlways,
 		AlgorithmParams: keyParams{
-			AlgID:     algRSA,
+			AlgID:     AlgRSA,
 			EncScheme: esNone,
 			SigScheme: ssRSASaPKCS1v15DER,
 			Params:    rParamsPacked,
diff --git a/tpm/verify.go b/tpm/verify.go
index 2eccac3..e578224 100644
--- a/tpm/verify.go
+++ b/tpm/verify.go
@@ -43,7 +43,7 @@ func UnmarshalRSAPublicKey(keyBlob []byte) (*rsa.PublicKey, error) {
 // unmarshalRSAPublicKey unmarshals a TPM key into a crypto/rsa.PublicKey.
 func (k *key) unmarshalRSAPublicKey() (*rsa.PublicKey, error) {
 	// Currently, we only support algRSA
-	if k.AlgorithmParams.AlgID != algRSA {
+	if k.AlgorithmParams.AlgID != AlgRSA {
 		return nil, errors.New("only TPM_ALG_RSA is supported")
 	}
 
@@ -81,8 +81,8 @@ func UnmarshalPubRSAPublicKey(keyBlob []byte) (*rsa.PublicKey, error) {
 // unmarshalRSAPublicKey unmarshals a TPM pub key into a crypto/rsa.PublicKey.
 // This is almost identical to the identically named function for a TPM key.
 func (pk *pubKey) unmarshalRSAPublicKey() (*rsa.PublicKey, error) {
-	// Currently, we only support algRSA
-	if pk.AlgorithmParams.AlgID != algRSA {
+	// Currently, we only support AlgRSA
+	if pk.AlgorithmParams.AlgID != AlgRSA {
 		return nil, errors.New("only TPM_ALG_RSA is supported")
 	}
 


Test patch:
diff --git a/tpm/tpm_test.go b/tpm/tpm_test.go
index baf2f5a..87136c7 100644
--- a/tpm/tpm_test.go
+++ b/tpm/tpm_test.go
@@ -70,6 +70,37 @@ func TestGetManufacturer(t *testing.T) {
 	t.Logf("TPM VendorID: %v\n", vendorID)
 }
 
+func TestGetAlgs(t *testing.T) {
+	rwc := openTPMOrSkip(t)
+	defer rwc.Close()
+
+	algs, err := GetAlgs(rwc)
+	if err != nil {
+		t.Fatalf("Couldn't read Algorithms: %v", err)
+	}
+	want := []Algorithm{AlgRSA, AlgSHA, AlgHMAC, AlgMGF1}
+outer:
+	for _, alg := range want {
+		for _, got := range algs {
+			if got == alg {
+				continue outer
+			}
+			t.Errorf("GetAlgs returned %v, which does not contain a required algorithm %v", algs, alg.String())
+		}
+	}
+}
+
+func TestGetNVList(t *testing.T) {
+	rwc := openTPMOrSkip(t)
+	defer rwc.Close()
+
+	nvList, err := GetNVList(rwc)
+	if err != nil {
+		t.Fatalf("Couldn't read NVList %v", err)
+	}
+	t.Logf("NVList is: %v", nvList)
+}
+
 func TestPcrExtend(t *testing.T) {
 	rwc := openTPMOrSkip(t)
 	defer rwc.Close()