Skip to content

Commit 6842806

Browse files
committed
refactor: update preimage marshal/unmarshal logic
1 parent 59f5c5a commit 6842806

File tree

2 files changed

+65
-69
lines changed

2 files changed

+65
-69
lines changed

tpm2/marshalling.go

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,39 +27,71 @@ type marshallableWithHint interface {
2727
// This structure is marshaled to bytes using [Marshal] for storage/transmission
2828
// and can be converted to the raw cpHash preimage format for hashing.
2929
//
30-
// Format when marshaled:
31-
// - CommandCode: 4 bytes (TPMCC)
32-
// - Names: sized list of TPM2BName
33-
// - Parameters: sized buffer
34-
//
3530
// See definition in Part 1: Architecture, section 16.7.
3631
type CommandPreimage struct {
37-
marshalByReflection
3832
// CommandCode is the TPM command code
3933
CommandCode TPMCC
4034
// Names are the names of the handles referenced by the command
41-
Names []TPM2BName `gotpm:"list"`
35+
Names []TPM2BName
4236
// Parameters are the marshaled command parameters
4337
Parameters TPM2BData
4438
}
4539

46-
// ToCPHashPreimage converts the CommandPreimage to the raw buffer format
47-
// used to compute cpHash according to TPM 2.0 spec.
48-
func (cp *CommandPreimage) ToCPHashPreimage() []byte {
49-
var buf bytes.Buffer
50-
51-
// Write command code (4 bytes, big endian)
52-
binary.Write(&buf, binary.BigEndian, cp.CommandCode)
53-
54-
// Write names (raw buffers without size prefix)
40+
// Marshal converts the CommandPreimage to its byte representation.
41+
//
42+
// Format:
43+
// - CommandCode: 4 bytes (TPMCC)
44+
// - NameCount: 4 bytes (uint32)
45+
// - For each Name:
46+
// - NameSize: 4 bytes (uint32)
47+
// - Parameters: remaining bytes
48+
func (cp *CommandPreimage) Marshal() ([]byte, error) {
49+
buf := new(bytes.Buffer)
50+
if err := binary.Write(buf, binary.BigEndian, cp.CommandCode); err != nil {
51+
return nil, err
52+
}
53+
if err := binary.Write(buf, binary.BigEndian, uint32(len(cp.Names))); err != nil {
54+
return nil, err
55+
}
5556
for _, name := range cp.Names {
57+
if err := binary.Write(buf, binary.BigEndian, uint32(len(name.Buffer))); err != nil {
58+
return nil, err
59+
}
5660
buf.Write(name.Buffer)
5761
}
58-
59-
// Write parameters
6062
buf.Write(cp.Parameters.Buffer)
63+
return buf.Bytes(), nil
64+
}
6165

62-
return buf.Bytes()
66+
// Unmarshal populates the [CommandPreimage] from its byte representation.
67+
func (cp *CommandPreimage) Unmarshal(b []byte) error {
68+
buf := bytes.NewBuffer(b)
69+
70+
if err := binary.Read(buf, binary.BigEndian, &cp.CommandCode); err != nil {
71+
return fmt.Errorf("unmarshalling CommandCode: %w", err)
72+
}
73+
74+
var nameCount uint32
75+
if err := binary.Read(buf, binary.BigEndian, &nameCount); err != nil {
76+
return fmt.Errorf("unmarshalling Names count: %w", err)
77+
}
78+
79+
cp.Names = make([]TPM2BName, nameCount)
80+
for i := uint32(0); i < nameCount; i++ {
81+
var name TPM2BName
82+
83+
var nameSize uint32
84+
if err := binary.Read(buf, binary.BigEndian, &nameSize); err != nil {
85+
return fmt.Errorf("unmarshalling Name size %d: %w", i, err)
86+
}
87+
name.Buffer = make([]byte, nameSize)
88+
if _, err := buf.Read(name.Buffer); err != nil {
89+
return fmt.Errorf("unmarshalling Name %d: %w", i, err)
90+
}
91+
cp.Names[i] = name
92+
}
93+
cp.Parameters.Buffer = buf.Bytes()
94+
return nil
6395
}
6496

6597
// Unmarshallable represents any TPM type that can be marshalled or unmarshalled.
@@ -196,15 +228,16 @@ func toCommandPreimage[C Command[R, *R], R any](cmd C) (*CommandPreimage, error)
196228
// - Names (sized list)
197229
// - Parameters (sized buffer)
198230
//
199-
// This can be stored, transmitted, or later unmarshaled.
231+
// This can be stored, transmitted, or later unmarshaled [UnmarshalCommand].
200232
//
201-
// To compute cpHash use [CommandPreimage.ToCPHashPreimage].
233+
// Note: Encrypted command parameters (via sessions) are not currently supported.
234+
// The marshaled parameters are in their unencrypted form.
202235
func MarshalCommand[C Command[R, *R], R any](cmd C) ([]byte, error) {
203236
preimage, err := toCommandPreimage(cmd)
204237
if err != nil {
205238
return nil, err
206239
}
207-
return Marshal(preimage), nil
240+
return preimage.Marshal()
208241
}
209242

210243
// unmarshalCommandPreimage unmarshals serialized data into CommandPreimage components.
@@ -214,8 +247,8 @@ func unmarshalCommandPreimage(data []byte) (TPMCC, []TPM2BName, []byte, error) {
214247
return 0, nil, nil, fmt.Errorf("data cannot be nil")
215248
}
216249

217-
preimage, err := Unmarshal[CommandPreimage](data)
218-
if err != nil {
250+
var preimage CommandPreimage
251+
if err := preimage.Unmarshal(data); err != nil {
219252
return 0, nil, nil, fmt.Errorf("unmarshalling CommandPreimage: %w", err)
220253
}
221254

@@ -225,8 +258,10 @@ func unmarshalCommandPreimage(data []byte) (TPMCC, []TPM2BName, []byte, error) {
225258
// UnmarshalCommand unmarshals a serialized [CommandPreimage] back into a TPM command.
226259
// The data should be the output from [MarshalCommand].
227260
//
228-
// Note: command produced from this function is not meant to be executed directly on a TPM,
229-
// instead it is expected to be used for purposes such as auditing or inspection.
261+
// Notes:
262+
// - command produced from this function is not meant to be executed directly on a TPM,
263+
// instead it is expected to be used for purposes such as auditing or inspection.
264+
// - encrypted command parameters (via sessions) are not currently supported.
230265
func UnmarshalCommand[C Command[R, *R], R any](data []byte) (C, error) {
231266
var cmd C
232267

@@ -271,7 +306,10 @@ func MarshalResponse[R any](rsp *R) ([]byte, error) {
271306

272307
// UnmarshalResponse unmarshals a TPM response.
273308
//
274-
// Note: the result from this function is expected to be used for purposes such as auditing or inspection.
309+
// Notes:
310+
// - the result from this function is expected to be used for purposes such as auditing or inspection.
311+
// - encrypted response parameters (via sessions) are not currently supported.
312+
// The marshaled parameters are always in their unencrypted form.
275313
func UnmarshalResponse[R any](data []byte) (*R, error) {
276314
var rsp R
277315
if data == nil {

tpm2/marshalling_test.go

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package tpm2
22

33
import (
44
"bytes"
5-
"encoding/binary"
65
"reflect"
76
"testing"
87

@@ -391,44 +390,3 @@ func TestCommandPreimage(t *testing.T) {
391390
})
392391
}
393392
}
394-
func TestCommandPreimageToCPHash(t *testing.T) {
395-
getCmd := GetCapability{
396-
Capability: TPMCapTPMProperties,
397-
Property: uint32(TPMPTFamilyIndicator),
398-
PropertyCount: 1,
399-
}
400-
401-
cmdBytes, err := MarshalCommand(getCmd)
402-
if err != nil {
403-
t.Fatalf("MarshalCommand failed: %v", err)
404-
}
405-
406-
cc, names, params, err := unmarshalCommandPreimage(cmdBytes)
407-
if err != nil {
408-
t.Fatalf("unmarshalCommandPreimage failed: %v", err)
409-
}
410-
411-
preimage := &CommandPreimage{
412-
CommandCode: cc,
413-
Names: names,
414-
Parameters: TPM2BData{
415-
Buffer: params,
416-
},
417-
}
418-
419-
cpHashPreimage := preimage.ToCPHashPreimage()
420-
421-
if len(cpHashPreimage) < 4 {
422-
t.Fatalf("cpHash preimage too short: %d bytes", len(cpHashPreimage))
423-
}
424-
425-
var ccFromPreimage TPMCC
426-
buf := bytes.NewReader(cpHashPreimage[:4])
427-
if err := binary.Read(buf, binary.BigEndian, &ccFromPreimage); err != nil {
428-
t.Fatalf("reading command code from preimage: %v", err)
429-
}
430-
431-
if ccFromPreimage != TPMCCGetCapability {
432-
t.Errorf("command code mismatch: want %v, got %v", TPMCCGetCapability, ccFromPreimage)
433-
}
434-
}

0 commit comments

Comments
 (0)