File: audit.go

package info (click to toggle)
golang-github-google-go-tpm 0.9.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,932 kB
  • sloc: makefile: 13
file content (87 lines) | stat: -rw-r--r-- 2,367 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package tpm2

import (
	"bytes"
	"fmt"
	"reflect"
)

// CommandAudit represents an audit session for attesting the execution of a
// series of commands in the TPM. It is useful for both command and session
// auditing.
type CommandAudit struct {
	hash   TPMIAlgHash
	digest []byte
}

// NewAudit initializes a new CommandAudit with the specified hash algorithm.
func NewAudit(hash TPMIAlgHash) (*CommandAudit, error) {
	h, err := hash.Hash()
	if err != nil {
		return nil, err
	}
	return &CommandAudit{
		hash:   hash,
		digest: make([]byte, h.Size()),
	}, nil
}

// AuditCommand extends the audit digest with the given command and response.
// Go Generics do not allow type parameters on methods, otherwise this would be
// a method on CommandAudit.
// See https://github.com/golang/go/issues/49085 for more information.
func AuditCommand[C Command[R, *R], R any](a *CommandAudit, cmd C, rsp *R) error {
	cc := cmd.Command()
	cpHash, err := auditCPHash[R](cc, a.hash, cmd)
	if err != nil {
		return err
	}
	rpHash, err := auditRPHash(cc, a.hash, rsp)
	if err != nil {
		return err
	}
	ha, err := a.hash.Hash()
	if err != nil {
		return err
	}
	h := ha.New()
	h.Write(a.digest)
	h.Write(cpHash)
	h.Write(rpHash)
	a.digest = h.Sum(nil)
	return nil
}

// Digest returns the current digest of the audit.
func (a *CommandAudit) Digest() []byte {
	return a.digest
}

// auditCPHash calculates the command parameter hash for a given command with
// the given hash algorithm. The command is assumed to not have any decrypt
// sessions.
func auditCPHash[R any](cc TPMCC, h TPMIAlgHash, c Command[R, *R]) ([]byte, error) {
	names, err := cmdNames(c)
	if err != nil {
		return nil, err
	}
	parms, err := cmdParameters(c, nil)
	if err != nil {
		return nil, err
	}
	return cpHash(h, cc, names, parms)
}

// auditRPHash calculates the response parameter hash for a given response with
// the given hash algorithm. The command is assumed to be successful and to not
// have any encrypt sessions.
func auditRPHash(cc TPMCC, h TPMIAlgHash, r any) ([]byte, error) {
	var parms bytes.Buffer
	parameters := taggedMembers(reflect.ValueOf(r).Elem(), "handle", true)
	for i, parameter := range parameters {
		if err := marshal(&parms, parameter); err != nil {
			return nil, fmt.Errorf("marshalling parameter %v: %w", i+1, err)
		}
	}
	return rpHash(h, TPMRCSuccess, cc, parms.Bytes())
}