Repository: google/go-tpm
Pull request #185 (2020-06-25 11:45:10)

TPM12: Exports NVPermissions, Localities, Digest, Nonce
Removed unused const digestSize, nonceSize

ChriMarMe: --- PASS: TestUnpackMalformedBytes (0.00s)
=== RUN   TestPoll
--- PASS: TestPoll (0.00s)
PASS
ok  	github.com/google/go-tpm/tpmutil	0.078s
?   	github.com/google/go-tpm/tpmutil/mssim	[no test files]
FAIL

I have no idea what's going on ¯\_(ツ)_/¯
ChriMarMe: This is work in progress. When ready for final review I will ping!
ChriMarMe: Ok, if @twitchy-jsonp  or @josephlr could have a look and tell me why the tests fail, I would fix it and we'll good to go for merging :)
twitchy-jsonp: Not sure whats going on, that cirrus output seems to be missing some detail.

Running `go test -v ./...` in a fresh machine has a few failures, but not sure if the cirrus setup has the dependencies necessary to avoid them.

```
jsonp@RedShell:~/go-tpm> go test -v ./...
go: downloading github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845
go: extracting github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845
# github.com/google/go-tpm-tools/simulator/internal
In file included from /home/jsonp/go/pkg/mod/github.com/google/go-tpm-tools@v0.0.0-20190906225433-1614c142f845/simulator/ms-tpm-20-ref/TPMCmd/tpm/include/LibSupport.h:54:0,
                 from /home/jsonp/go/pkg/mod/github.com/google/go-tpm-tools@v0.0.0-20190906225433-1614c142f845/simulator/ms-tpm-20-ref/TPMCmd/tpm/include/Tpm.h:47,
                 from ../go/pkg/mod/github.com/google/go-tpm-tools@v0.0.0-20190906225433-1614c142f845/simulator/internal/internal.go:39:
/home/jsonp/go/pkg/mod/github.com/google/go-tpm-tools@v0.0.0-20190906225433-1614c142f845/simulator/ms-tpm-20-ref/TPMCmd/tpm/include/Ossl/TpmToOsslSym.h:47:25: fatal error: openssl/aes.h: No such file or directory
 #include <openssl/aes.h>
                         ^
compilation terminated.
# github.com/google/go-tpm/tpm [github.com/google/go-tpm/tpm.test]
tpm/pcrs_test.go:142:40: undefined: locZero
tpm/tpm_test.go:40:27: undefined: digest
tpm/tpm_test.go:41:11: undefined: digest
tpm/tpm_test.go:235:43: undefined: locZero
tpm/tpm_test.go:239:44: undefined: locZero
tpm/tpm_test.go:243:42: undefined: nvPerOwnerWrite
tpm/tpm_test.go:324:27: undefined: locZero
tpm/tpm_test.go:352:29: undefined: locZero
?   	github.com/google/go-tpm/examples/tpm-clear	[no test files]
?   	github.com/google/go-tpm/examples/tpm-genaik	[no test files]
?   	github.com/google/go-tpm/examples/tpm-keys	[no test files]
?   	github.com/google/go-tpm/examples/tpm-sign	[no test files]
?   	github.com/google/go-tpm/examples/tpm-takeownership	[no test files]
?   	github.com/google/go-tpm/examples/tpm2-ekcert	[no test files]
?   	github.com/google/go-tpm/examples/tpm2-nvread	[no test files]
?   	github.com/google/go-tpm/examples/tpm2-seal-unseal	[no test files]
FAIL	github.com/google/go-tpm/tpm [build failed]
=== RUN   TestEncodeDecodeCreationData
--- PASS: TestEncodeDecodeCreationData (0.00s)
=== RUN   TestDecodeReadPCRs
--- PASS: TestDecodeReadPCRs (0.00s)
=== RUN   TestSingleEncodeDecodeTPMLSelection
--- PASS: TestSingleEncodeDecodeTPMLSelection (0.00s)
=== RUN   TestMultiArgsEncodeDecodeTPMLSelection
--- PASS: TestMultiArgsEncodeDecodeTPMLSelection (0.00s)
=== RUN   TestDecodeReadClock
--- PASS: TestDecodeReadClock (0.00s)
=== RUN   TestDecodeGetCapability
--- PASS: TestDecodeGetCapability (0.00s)
=== RUN   TestEncodeLoad
--- PASS: TestEncodeLoad (0.00s)
=== RUN   TestDecodeLoad
--- PASS: TestDecodeLoad (0.00s)
=== RUN   TestEncodeCreate
--- PASS: TestEncodeCreate (0.00s)
=== RUN   TestDecodeCreatePrimary
--- PASS: TestDecodeCreatePrimary (0.00s)
=== RUN   TestEncodePolicyPCR
--- PASS: TestEncodePolicyPCR (0.00s)
=== RUN   TestDecodeStartAuthSession
--- PASS: TestDecodeStartAuthSession (0.00s)
=== RUN   TestDecodeCreate
--- PASS: TestDecodeCreate (0.00s)
=== RUN   TestEncodeUnseal
--- PASS: TestEncodeUnseal (0.00s)
=== RUN   TestDecodeUnseal
--- PASS: TestDecodeUnseal (0.00s)
=== RUN   TestEncodeQuote
--- PASS: TestEncodeQuote (0.00s)
=== RUN   TestDecodeQuote
--- PASS: TestDecodeQuote (0.00s)
=== RUN   TestDecodeReadPublic
--- PASS: TestDecodeReadPublic (0.00s)
=== RUN   TestEncodeEvictControl
--- PASS: TestEncodeEvictControl (0.00s)
=== RUN   TestEncodeAuthArea
--- PASS: TestEncodeAuthArea (0.00s)
=== RUN   TestEncodeSensitiveArea
--- PASS: TestEncodeSensitiveArea (0.00s)
=== RUN   TestEncodeTPMLPCRSelection
--- PASS: TestEncodeTPMLPCRSelection (0.00s)
=== RUN   TestECCParamsEncodeDecode
--- PASS: TestECCParamsEncodeDecode (0.01s)
=== RUN   TestSignEncode
=== RUN   TestSignEncode/AlgNull
=== RUN   TestSignEncode/AlgSHA256
--- PASS: TestSignEncode (0.00s)
    --- PASS: TestSignEncode/AlgNull (0.00s)
    --- PASS: TestSignEncode/AlgSHA256 (0.00s)
=== RUN   TestError
--- PASS: TestError (0.00s)
=== RUN   TestRunCommandErr
--- PASS: TestRunCommandErr (0.00s)
PASS
ok  	github.com/google/go-tpm/tpm2	0.037s
=== RUN   TestCredentialActivation
--- PASS: TestCredentialActivation (0.00s)
PASS
ok  	github.com/google/go-tpm/tpm2/credactivation	0.028s
FAIL	github.com/google/go-tpm/tpm2/test [build failed]
=== RUN   TestEmulatorReadWriteCloserMultipleReads
--- PASS: TestEmulatorReadWriteCloserMultipleReads (0.00s)
=== RUN   TestEmulatorReadWriteCloserClose
--- PASS: TestEmulatorReadWriteCloserClose (0.00s)
=== RUN   TestEmulatorReadWriteCloseReadAfterClose
--- PASS: TestEmulatorReadWriteCloseReadAfterClose (0.00s)
=== RUN   TestEmulatorReadWriteCloserReadBeforeWrite
--- PASS: TestEmulatorReadWriteCloserReadBeforeWrite (0.00s)
=== RUN   TestEmulatorReadWriteCloserDoubleWrite
--- PASS: TestEmulatorReadWriteCloserDoubleWrite (0.00s)
=== RUN   TestEmulatorReadWriteCloserDialerError
--- PASS: TestEmulatorReadWriteCloserDialerError (0.00s)
=== RUN   TestEncodingPackTypeInvalid
--- PASS: TestEncodingPackTypeInvalid (0.00s)
=== RUN   TestEncodingPackType
--- PASS: TestEncodingPackType (0.00s)
=== RUN   TestEncodingPackTypeWriteFail
--- PASS: TestEncodingPackTypeWriteFail (0.00s)
=== RUN   TestEncodingCommandHeaderInvalidBody
--- PASS: TestEncodingCommandHeaderInvalidBody (0.00s)
=== RUN   TestEncodingInvalidPack
--- PASS: TestEncodingInvalidPack (0.00s)
=== RUN   TestEncodingCommandHeaderEncoding
--- PASS: TestEncodingCommandHeaderEncoding (0.00s)
=== RUN   TestEncodingInvalidUnpack
--- PASS: TestEncodingInvalidUnpack (0.00s)
=== RUN   TestSelfMarshaler
--- PASS: TestSelfMarshaler (0.00s)
    encoding_test.go:232: Attempting to Marshal/Unmarshal []byte{0x0, 0x0} into *tpmutil.U16Bytes
    encoding_test.go:232: Attempting to Marshal/Unmarshal []byte{0x0, 0x1, 0x89} into *tpmutil.U16Bytes
    encoding_test.go:232: Attempting to Marshal/Unmarshal []byte{0x0, 0x0, 0x0, 0x0} into *tpmutil.U32Bytes
    encoding_test.go:232: Attempting to Marshal/Unmarshal []byte{0x0, 0x0, 0x0, 0x1, 0x89} into *tpmutil.U32Bytes
=== RUN   TestEncodingUnpack
--- PASS: TestEncodingUnpack (0.00s)
=== RUN   TestPartialUnpack
--- PASS: TestPartialUnpack (0.00s)
=== RUN   TestUnpackHandlesArea
--- PASS: TestUnpackHandlesArea (0.00s)
=== RUN   TestUnpackMalformedBytes
--- PASS: TestUnpackMalformedBytes (0.00s)
=== RUN   TestPoll
--- PASS: TestPoll (0.00s)
PASS
ok  	github.com/google/go-tpm/tpmutil	0.050s
?   	github.com/google/go-tpm/tpmutil/mssim	[no test files]
```
twitchy-jsonp: Oh okay found it I think (I got the dependencies installed but still have this error):

```
# github.com/google/go-tpm/tpm [github.com/google/go-tpm/tpm.test]
tpm/pcrs_test.go:142:40: undefined: locZero
tpm/tpm_test.go:40:27: undefined: digest
tpm/tpm_test.go:41:11: undefined: digest
tpm/tpm_test.go:235:43: undefined: locZero
tpm/tpm_test.go:239:44: undefined: locZero
tpm/tpm_test.go:243:42: undefined: nvPerOwnerWrite
tpm/tpm_test.go:324:27: undefined: locZero
tpm/tpm_test.go:352:29: undefined: locZero
FAIL	github.com/google/go-tpm/tpm [build failed]
```
ChriMarMe: @twitchy-jsonp Thank a lot :) next time please hit me with a hammer :)
I just "tested" the go build, but not go test....so i missed to change the tests xD
Sorry to bother you but I'm thankful for your help. 



Patch:
diff --git a/tpm/commands.go b/tpm/commands.go
index 7af3685..43b22d9 100644
--- a/tpm/commands.go
+++ b/tpm/commands.go
@@ -159,7 +159,7 @@ func getCapability(rw io.ReadWriter, cap, subcap uint32) ([]byte, error) {
 }
 
 // nvDefineSpace allocates space in NVRAM
-func nvDefineSpace(rw io.ReadWriter, nvData NVDataPublic, enc digest, ca *commandAuth) (*responseAuth, uint32, error) {
+func nvDefineSpace(rw io.ReadWriter, nvData NVDataPublic, enc Digest, ca *commandAuth) (*responseAuth, uint32, error) {
 	var ra responseAuth
 	in := []interface{}{nvData, enc}
 	if ca != nil {
@@ -299,7 +299,7 @@ func quote(rw io.ReadWriter, keyHandle tpmutil.Handle, hash [20]byte, pcrs *pcrS
 
 // makeIdentity requests that the TPM create a new AIK. It returns the handle to
 // this new key.
-func makeIdentity(rw io.ReadWriter, encAuth digest, idDigest digest, k *key, ca1 *commandAuth, ca2 *commandAuth) (*key, []byte, *responseAuth, *responseAuth, uint32, error) {
+func makeIdentity(rw io.ReadWriter, encAuth Digest, idDigest Digest, k *key, ca1 *commandAuth, ca2 *commandAuth) (*key, []byte, *responseAuth, *responseAuth, uint32, error) {
 	in := []interface{}{encAuth, idDigest, k, ca1, ca2}
 	var aik key
 	var sig tpmutil.U32Bytes
@@ -363,10 +363,10 @@ func ownerReadInternalPub(rw io.ReadWriter, kh tpmutil.Handle, ca *commandAuth)
 // that this call can only be made when there is no owner in the TPM. Once an
 // owner is established, the endorsement key can be retrieved using
 // ownerReadInternalPub.
-func readPubEK(rw io.ReadWriter, n nonce) (*pubKey, digest, uint32, error) {
+func readPubEK(rw io.ReadWriter, n Nonce) (*pubKey, Digest, uint32, error) {
 	in := []interface{}{n}
 	var pk pubKey
-	var d digest
+	var d Digest
 	out := []interface{}{&pk, &d}
 	ret, err := submitTPMRequest(rw, tagRQUCommand, ordReadPubEK, in, out)
 	if err != nil {
@@ -408,7 +408,7 @@ func takeOwnership(rw io.ReadWriter, encOwnerAuth tpmutil.U32Bytes, encSRKAuth t
 }
 
 // Creates a wrapped key under the SRK.
-func createWrapKey(rw io.ReadWriter, encUsageAuth digest, encMigrationAuth digest, keyInfo *key, ca *commandAuth) (*key, *responseAuth, uint32, error) {
+func createWrapKey(rw io.ReadWriter, encUsageAuth Digest, encMigrationAuth Digest, keyInfo *key, ca *commandAuth) (*key, *responseAuth, uint32, error) {
 	in := []interface{}{khSRK, encUsageAuth, encMigrationAuth, keyInfo, ca}
 	var k key
 	var ra responseAuth
diff --git a/tpm/constants.go b/tpm/constants.go
index 40db914..3e2452d 100644
--- a/tpm/constants.go
+++ b/tpm/constants.go
@@ -69,30 +69,30 @@ const (
 
 // Capability types.
 const (
-	capAlg      uint32 = 0x00000002
-	capProperty uint32 = 0x00000005
-	capFlag     uint32 = 0x00000004
-	capNVList   uint32 = 0x0000000D
-	capNVIndex  uint32 = 0x00000011
-	capHandle   uint32 = 0x00000014
+	CapAlg      uint32 = 0x00000002
+	CapProperty uint32 = 0x00000005
+	CapFlag     uint32 = 0x00000004
+	CapNVList   uint32 = 0x0000000D
+	CapNVIndex  uint32 = 0x00000011
+	CapHandle   uint32 = 0x00000014
 )
 
 // SubCapabilities
 const (
-	tpmCapPropManufacturer uint32 = 0x00000103
-	tpmCapFlagPermanent    uint32 = 0x00000108
+	SubCapPropManufacturer uint32 = 0x00000103
+	SubCapFlagPermanent    uint32 = 0x00000108
 )
 
-// permission type
-type permission uint32
+// 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
+	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
@@ -103,30 +103,30 @@ const (
 	// 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
+	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",
+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 {
+func (p Permission) String() string {
 	var retString strings.Builder
 	for iterator, item := range permMap {
 		if (p & iterator) != 0 {
@@ -167,20 +167,20 @@ type Locality byte
 // Values of locality
 // Note: Localities are summable
 const (
-	locZero Locality = 1 << iota
-	locOne
-	locTwo
-	locThree
-	locFour
+	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",
+	LocZero:  "Locality 0",
+	LocOne:   "Locality 1",
+	LocTwo:   "Locality 2",
+	LocThree: "Locality 3",
+	LocFour:  "Locality 4",
 }
 
 // // String returns a textual representation of the set of Localities
diff --git a/tpm/structures.go b/tpm/structures.go
index 07a1af7..0e5b6ad 100644
--- a/tpm/structures.go
+++ b/tpm/structures.go
@@ -50,21 +50,21 @@ type pcrInfoLong struct {
 	LocAtRelease     Locality
 	PCRsAtCreation   pcrSelection
 	PCRsAtRelease    pcrSelection
-	DigestAtCreation digest
-	DigestAtRelease  digest
+	DigestAtCreation Digest
+	DigestAtRelease  Digest
 }
 
 // pcrInfoShort stores detailed information about PCRs.
 type pcrInfoShort struct {
 	PCRsAtRelease   pcrSelection
 	LocAtRelease    Locality
-	DigestAtRelease digest
+	DigestAtRelease Digest
 }
 
 type pcrInfo struct {
 	PcrSelection     pcrSelection
-	DigestAtRelease  digest
-	DigestAtCreation digest
+	DigestAtRelease  Digest
+	DigestAtCreation Digest
 }
 
 // A capVersionInfo contains information about the TPM itself. Note that this
@@ -113,7 +113,7 @@ type PermanentFlags struct {
 // See: TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011, P.140
 type nvAttributes struct {
 	Tag        uint16
-	Attributes permission
+	Attributes Permission
 }
 
 // NVDataPublic implements the structure of TPM_NV_DATA_PUBLIC
@@ -135,15 +135,13 @@ func CloseKey(rw io.ReadWriter, h tpmutil.Handle) error {
 	return flushSpecific(rw, h, rtKey)
 }
 
-// A nonce is a 20-byte value.
-type nonce [20]byte
-
-const nonceSize uint32 = 20
+// A Nonce is a 20-byte value.
+type Nonce [20]byte
 
 // An oiapResponse is a response to an OIAP command.
 type oiapResponse struct {
 	AuthHandle tpmutil.Handle
-	NonceEven  nonce
+	NonceEven  Nonce
 }
 
 // String returns a string representation of an oiapResponse.
@@ -160,7 +158,7 @@ func (opr *oiapResponse) Close(rw io.ReadWriter) error {
 type osapCommand struct {
 	EntityType  uint16
 	EntityValue tpmutil.Handle
-	OddOSAP     nonce
+	OddOSAP     Nonce
 }
 
 // String returns a string representation of an osapCommand.
@@ -171,8 +169,8 @@ func (opc osapCommand) String() string {
 // An osapResponse is a TPM reply to an osapCommand.
 type osapResponse struct {
 	AuthHandle tpmutil.Handle
-	NonceEven  nonce
-	EvenOSAP   nonce
+	NonceEven  Nonce
+	EvenOSAP   Nonce
 }
 
 // String returns a string representation of an osapResponse.
@@ -186,9 +184,7 @@ func (opr *osapResponse) Close(rw io.ReadWriter) error {
 }
 
 // A Digest is a 20-byte SHA1 value.
-type digest [20]byte
-
-const digestSize uint32 = 20
+type Digest [20]byte
 
 // An AuthValue is a 20-byte value used for authentication.
 type authValue [20]byte
@@ -211,7 +207,7 @@ func (sc sealCommand) String() string {
 // tagRQUAuth2Command use two.
 type commandAuth struct {
 	AuthHandle  tpmutil.Handle
-	NonceOdd    nonce
+	NonceOdd    Nonce
 	ContSession byte
 	Auth        authValue
 }
@@ -223,7 +219,7 @@ func (ca commandAuth) String() string {
 
 // responseAuth contains the auth information returned from a command.
 type responseAuth struct {
-	NonceEven   nonce
+	NonceEven   Nonce
 	ContSession byte
 	Auth        authValue
 }
@@ -315,10 +311,10 @@ type quoteInfo struct {
 	Fixed [4]byte
 
 	// The CompositeDigest is computed by ComputePCRComposite.
-	CompositeDigest digest
+	CompositeDigest Digest
 
-	// The nonce is either a random nonce or the SHA1 hash of data to sign.
-	Nonce nonce
+	// The Nonce is either a random Nonce or the SHA1 hash of data to sign.
+	Nonce Nonce
 }
 
 // A pcrComposite stores a selection of PCRs with the selected PCR values.
diff --git a/tpm/tpm.go b/tpm/tpm.go
index d3afab5..60c5db8 100644
--- a/tpm/tpm.go
+++ b/tpm/tpm.go
@@ -34,7 +34,7 @@ import (
 
 // GetKeys gets the list of handles for currently-loaded TPM keys.
 func GetKeys(rw io.ReadWriter) ([]tpmutil.Handle, error) {
-	b, err := getCapability(rw, capHandle, rtKey)
+	b, err := getCapability(rw, CapHandle, rtKey)
 	if err != nil {
 		return nil, err
 	}
@@ -257,7 +257,7 @@ 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) {
+func newCommandAuth(authHandle tpmutil.Handle, nonceEven Nonce, key []byte, params []interface{}) (*commandAuth, error) {
 	// Auth = HMAC-SHA1(key, SHA1(params) || NonceEven || NonceOdd || ContSession)
 	digestBytes, err := tpmutil.Pack(params...)
 	if err != nil {
@@ -285,7 +285,7 @@ func newCommandAuth(authHandle tpmutil.Handle, nonceEven nonce, key []byte, para
 // verify checks that the response authentication was correct.
 // It computes the SHA1 of params, and computes the HMAC-SHA1 of this digest
 // with the authentication parameters of ra along with the given odd nonce.
-func (ra *responseAuth) verify(nonceOdd nonce, key []byte, params []interface{}) error {
+func (ra *responseAuth) verify(nonceOdd Nonce, key []byte, params []interface{}) error {
 	// Auth = HMAC-SHA1(key, SHA1(params) || ra.NonceEven || NonceOdd || ra.ContSession)
 	digestBytes, err := tpmutil.Pack(params...)
 	if err != nil {
@@ -529,12 +529,12 @@ func MakeIdentity(rw io.ReadWriter, srkAuth []byte, ownerAuth []byte, aikAuth []
 	defer zeroBytes(xorData)
 
 	encAuthData := sha1.Sum(xorData)
-	var encAuth digest
+	var encAuth Digest
 	for i := range encAuth {
 		encAuth[i] = aikAuth[i] ^ encAuthData[i]
 	}
 
-	var caDigest digest
+	var caDigest Digest
 	if (pk != nil) != (label != nil) {
 		return nil, errors.New("inconsistent null values between the pk and the label")
 	}
@@ -742,7 +742,7 @@ func ActivateIdentity(rw io.ReadWriter, aikAuth []byte, ownerAuth []byte, aik tp
 // TPM to start working again after authentication errors without waiting for
 // the dictionary-attack defenses to time out. This requires owner
 // authentication.
-func ResetLockValue(rw io.ReadWriter, ownerAuth digest) error {
+func ResetLockValue(rw io.ReadWriter, ownerAuth Digest) error {
 	// Run OSAP for the Owner, reading a random OddOSAP for our initial command
 	// and getting back a secret and a handle.
 	sharedSecretOwn, osaprOwn, err := newOSAPSession(rw, etOwner, khOwner, ownerAuth[:])
@@ -779,7 +779,7 @@ func ResetLockValue(rw io.ReadWriter, ownerAuth digest) error {
 // ownerReadInternalHelper sets up command auth and checks response auth for
 // OwnerReadInternalPub. It's not exported because OwnerReadInternalPub only
 // supports two fixed key handles: khEK and khSRK.
-func ownerReadInternalHelper(rw io.ReadWriter, kh tpmutil.Handle, ownerAuth digest) (*pubKey, error) {
+func ownerReadInternalHelper(rw io.ReadWriter, kh tpmutil.Handle, ownerAuth Digest) (*pubKey, error) {
 	// Run OSAP for the Owner, reading a random OddOSAP for our initial command
 	// and getting back a secret and a handle.
 	sharedSecretOwn, osaprOwn, err := newOSAPSession(rw, etOwner, khOwner, ownerAuth[:])
@@ -814,7 +814,7 @@ func ownerReadInternalHelper(rw io.ReadWriter, kh tpmutil.Handle, ownerAuth dige
 }
 
 // OwnerReadSRK uses owner auth to get a blob representing the SRK.
-func OwnerReadSRK(rw io.ReadWriter, ownerAuth digest) ([]byte, error) {
+func OwnerReadSRK(rw io.ReadWriter, ownerAuth Digest) ([]byte, error) {
 	pk, err := ownerReadInternalHelper(rw, khSRK, ownerAuth)
 	if err != nil {
 		return nil, err
@@ -828,7 +828,7 @@ func OwnerReadSRK(rw io.ReadWriter, ownerAuth digest) ([]byte, error) {
 // here and return only the DER encoded certificate.
 // TCG PC Client Specific Implementation Specification for Conventional BIOS 7.4.4
 // https://www.trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientImplementation_1-21_1_00.pdf
-func ReadEKCert(rw io.ReadWriter, ownAuth digest) ([]byte, error) {
+func ReadEKCert(rw io.ReadWriter, ownAuth Digest) ([]byte, error) {
 	const (
 		certIndex                 = 0x1000f000 // TPM_NV_INDEX_EKCert (TPM Main Part 2 TPM Structures 19.1.2)
 		certTagPCClientStoredCert = 0x1001     // TCG_TAG_PCCLIENT_STORED_CERT
@@ -1076,7 +1076,7 @@ func NVWriteValueAuth(rw io.ReadWriter, index, offset uint32, data []byte, auth
 
 // OwnerReadPubEK uses owner auth to get a blob representing the public part of the
 // endorsement key.
-func OwnerReadPubEK(rw io.ReadWriter, ownerAuth digest) ([]byte, error) {
+func OwnerReadPubEK(rw io.ReadWriter, ownerAuth Digest) ([]byte, error) {
 	pk, err := ownerReadInternalHelper(rw, khEK, ownerAuth)
 	if err != nil {
 		return nil, err
@@ -1088,7 +1088,7 @@ func OwnerReadPubEK(rw io.ReadWriter, ownerAuth digest) ([]byte, error) {
 // ReadPubEK reads the public part of the endorsement key when no owner is
 // established.
 func ReadPubEK(rw io.ReadWriter) ([]byte, error) {
-	var n nonce
+	var n Nonce
 	if _, err := rand.Read(n[:]); err != nil {
 		return nil, err
 	}
@@ -1117,14 +1117,14 @@ func ReadPubEK(rw io.ReadWriter) ([]byte, error) {
 
 // GetManufacturer returns the manufacturer ID
 func GetManufacturer(rw io.ReadWriter) ([]byte, error) {
-	return getCapability(rw, capProperty, tpmCapPropManufacturer)
+	return getCapability(rw, CapProperty, SubCapPropManufacturer)
 }
 
 // GetPermanentFlags returns the TPM_PERMANENT_FLAGS structure.
 func GetPermanentFlags(rw io.ReadWriter) (PermanentFlags, error) {
 	var ret PermanentFlags
 
-	raw, err := getCapability(rw, capFlag, tpmCapFlagPermanent)
+	raw, err := getCapability(rw, CapFlag, SubCapFlagPermanent)
 	if err != nil {
 		return ret, err
 	}
@@ -1137,7 +1137,7 @@ func GetPermanentFlags(rw io.ReadWriter) (PermanentFlags, error) {
 func GetAlgs(rw io.ReadWriter) ([]Algorithm, error) {
 	var algs []Algorithm
 	for i := AlgRSA; i <= AlgXOR; i++ {
-		buf, err := getCapability(rw, capAlg, uint32(i))
+		buf, err := getCapability(rw, CapAlg, uint32(i))
 		if err != nil {
 			return nil, err
 		}
@@ -1152,7 +1152,7 @@ func GetAlgs(rw io.ReadWriter) ([]Algorithm, error) {
 // 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) {
-	buf, err := getCapability(rw, capNVList, 0)
+	buf, err := getCapability(rw, CapNVList, 0)
 	if err != nil {
 		return nil, err
 	}
@@ -1169,7 +1169,7 @@ func GetNVList(rw io.ReadWriter) ([]uint32, error) {
 // 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, _ := getCapability(rw, capNVIndex, nvIndex)
+	buf, _ := getCapability(rw, CapNVIndex, nvIndex)
 	if _, err := tpmutil.Unpack(buf, &nvInfo); err != nil {
 		return &nvInfo, err
 	}
@@ -1185,7 +1185,7 @@ func GetCapabilityRaw(rw io.ReadWriter, cap, subcap uint32) ([]byte, error) {
 
 // OwnerClear uses owner auth to clear the TPM. After this operation, the TPM
 // can change ownership.
-func OwnerClear(rw io.ReadWriter, ownerAuth digest) error {
+func OwnerClear(rw io.ReadWriter, ownerAuth Digest) error {
 	// Run OSAP for the Owner, reading a random OddOSAP for our initial command
 	// and getting back a secret and a handle.
 	sharedSecretOwn, osaprOwn, err := newOSAPSession(rw, etOwner, khOwner, ownerAuth[:])
@@ -1224,7 +1224,7 @@ func OwnerClear(rw io.ReadWriter, ownerAuth digest) error {
 // operation can only be performed if there isn't already an owner for the TPM.
 // The pub EK blob can be acquired by calling ReadPubEK if there is no owner, or
 // OwnerReadPubEK if there is.
-func TakeOwnership(rw io.ReadWriter, newOwnerAuth digest, newSRKAuth digest, pubEK []byte) error {
+func TakeOwnership(rw io.ReadWriter, newOwnerAuth Digest, newSRKAuth Digest, pubEK []byte) error {
 
 	// Encrypt the owner and SRK auth with the endorsement key.
 	ek, err := UnmarshalPubRSAPublicKey(pubEK)
@@ -1302,7 +1302,7 @@ func TakeOwnership(rw io.ReadWriter, newOwnerAuth digest, newSRKAuth digest, pub
 // 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 CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth Digest, migrationAuth Digest, pcrs []int) ([]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)
@@ -1319,11 +1319,11 @@ func CreateWrapKey(rw io.ReadWriter, srkAuth []byte, usageAuth digest, migration
 	defer zeroBytes(xorData)
 	encAuthDataKey := sha1.Sum(xorData)
 
-	var encUsageAuth digest
+	var encUsageAuth Digest
 	for i := range srkAuth {
 		encUsageAuth[i] = encAuthDataKey[i] ^ usageAuth[i]
 	}
-	var encMigrationAuth digest
+	var encMigrationAuth Digest
 	for i := range srkAuth {
 		encMigrationAuth[i] = encAuthDataKey[i] ^ migrationAuth[i]
 	}
diff --git a/tpm2/constants.go b/tpm2/constants.go
index 9adadad..9500a2e 100644
--- a/tpm2/constants.go
+++ b/tpm2/constants.go
@@ -18,6 +18,7 @@ import (
 	"crypto"
 	"crypto/elliptic"
 	"fmt"
+	"strings"
 
 	// Register the relevant hash implementations to prevent a runtime failure.
 	_ "crypto/sha1"
@@ -432,3 +433,42 @@ const (
 	AttrPlatformCreate NVAttr = 0x40000000
 	AttrReadSTClear    NVAttr = 0x80000000
 )
+
+var permMap = map[NVAttr]string{
+	AttrPPWrite:        "PPWrite",
+	AttrOwnerWrite:     "OwnerWrite",
+	AttrAuthWrite:      "AuthWrite",
+	AttrPolicyWrite:    "PolicyWrite",
+	AttrPolicyDelete:   "PolicyDelete",
+	AttrWriteLocked:    "WriteLocked",
+	AttrWriteAll:       "WriteAll",
+	AttrWriteDefine:    "WriteDefine",
+	AttrWriteSTClear:   "WriteSTClear",
+	AttrGlobalLock:     "GlobalLock",
+	AttrPPRead:         "PPRead",
+	AttrOwnerRead:      "OwnerRead",
+	AttrAuthRead:       "AuthRead",
+	AttrPolicyRead:     "PolicyRead",
+	AttrNoDA:           "No Do",
+	AttrOrderly:        "Oderly",
+	AttrClearSTClear:   "ClearSTClear",
+	AttrReadLocked:     "ReadLocked",
+	AttrWritten:        "Writte",
+	AttrPlatformCreate: "PlatformCreate",
+	AttrReadSTClear:    "ReadSTClear",
+}
+
+// String returns a textual representation of the set of NVAttr
+func (p NVAttr) 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(), " + ")
+
+}
diff --git a/tpm2/structures.go b/tpm2/structures.go
index da572d6..9584984 100644
--- a/tpm2/structures.go
+++ b/tpm2/structures.go
@@ -31,7 +31,7 @@ import (
 type NVPublic struct {
 	NVIndex    tpmutil.Handle
 	NameAlg    Algorithm
-	Attributes KeyProp
+	Attributes NVAttr
 	AuthPolicy tpmutil.U16Bytes
 	DataSize   uint16
 }


Test patch:
diff --git a/tpm/pcrs_test.go b/tpm/pcrs_test.go
index a8827ce..624cf1e 100644
--- a/tpm/pcrs_test.go
+++ b/tpm/pcrs_test.go
@@ -139,7 +139,7 @@ func TestNewPCRInfoLongWithHashes(t *testing.T) {
 	pcrMap[23] = make([]byte, 20)
 	pcrMap[16] = make([]byte, 20)
 
-	if _, err := newPCRInfoLongWithHashes(locZero, pcrMap); err != nil {
+	if _, err := newPCRInfoLongWithHashes(LocZero, pcrMap); err != nil {
 		t.Fatal("Couldn't create pcrInfoLong structure")
 	}
 }
diff --git a/tpm/tpm_test.go b/tpm/tpm_test.go
index bf8401d..a2f2d7e 100644
--- a/tpm/tpm_test.go
+++ b/tpm/tpm_test.go
@@ -37,8 +37,8 @@ var (
 // getAuth looks in the environment variables to find a given auth input value.
 // If the environment variable is not present, then getAuth returns the
 // well-known auth value of 20 bytes of zeros.
-func getAuth(name string) digest {
-	var auth digest
+func getAuth(name string) Digest {
+	var auth Digest
 	authInput := os.Getenv(name)
 	if authInput != "" {
 		aa := sha1.Sum([]byte(authInput))
@@ -198,7 +198,7 @@ func TestFetchPCRValues(t *testing.T) {
 		t.Fatal("Couldn't create PCR composite")
 	}
 
-	if len(comp) != int(digestSize) {
+	if len(comp) != int(20) {
 		t.Fatal("Invalid PCR composite")
 	}
 
@@ -232,15 +232,15 @@ func TestNVDefineSpace(t *testing.T) {
 	// TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011, P.139
 	owner := getAuth(ownerAuthEnvVar)
 	nvIndex := uint32(0x0000F004)
-	pcrInfoRead, err := newPCRInfoShort(rwc, locZero, []int{1})
+	pcrInfoRead, err := newPCRInfoShort(rwc, LocZero, []int{1})
 	if err != nil {
 		t.Fatalf("Couldn't create PCRInfoRead in define space")
 	}
-	pcrInfoWrite, err := newPCRInfoShort(rwc, locZero, []int{1})
+	pcrInfoWrite, err := newPCRInfoShort(rwc, LocZero, []int{1})
 	if err != nil {
 		t.Fatalf("Couldn't create PCRInfoWrite in define space")
 	}
-	nvAtt := &nvAttributes{tagNVAttributes, nvPerOwnerWrite}
+	nvAtt := &nvAttributes{tagNVAttributes, NVPerOwnerWrite}
 	nvData := NVDataPublic{tagNVDataPublic, nvIndex, *pcrInfoRead, *pcrInfoWrite, *nvAtt, true, true, false, uint32(20)}
 
 	err = NVDefineSpace(rwc, nvData, []byte(owner[:]))
@@ -321,7 +321,7 @@ func TestSeal(t *testing.T) {
 	data[2] = 139
 
 	srkAuth := getAuth(srkAuthEnvVar)
-	sealed, err := Seal(rwc, locZero, []int{17} /* PCR 17 */, data, srkAuth[:])
+	sealed, err := Seal(rwc, LocZero, []int{17} /* PCR 17 */, data, srkAuth[:])
 	if err != nil {
 		t.Fatal("Couldn't seal the data:", err)
 	}
@@ -349,7 +349,7 @@ func TestReseal(t *testing.T) {
 	pcrMap[23] = make([]byte, 20)
 	pcrMap[16] = make([]byte, 20)
 	srkAuth := getAuth(srkAuthEnvVar)
-	sealed, err := Reseal(rwc, locZero, pcrMap, data, srkAuth[:])
+	sealed, err := Reseal(rwc, LocZero, pcrMap, data, srkAuth[:])
 	if err != nil {
 		t.Fatal("Couldn't seal the data:", err)
 	}