Skip to content

Commit e9ffeca

Browse files
committed
tmputil: introduce non-global encoding logic
Right now it's not possible to use the tpm and tpm2 packages simultaneously. Refactor the encoding logic into separate structs, so using one doesn't impact the other, while maintaining the top level API. As a follow up, refactor the tpm and tpm2 packages to use the encoders. For example instead of: tpmutil.Pack(digest) Use: var encoding = tpmutil.Encoding1_2 encoding.Pack(digest)
1 parent 60fe40e commit e9ffeca

File tree

5 files changed

+129
-78
lines changed

5 files changed

+129
-78
lines changed

tpm/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import "github.com/google/go-tpm/tpmutil"
1818

1919
func init() {
2020
// TPM 1.2 spec uses uint32 for length prefix of byte arrays.
21-
tpmutil.UseTPM12LengthPrefixSize()
21+
tpmutil.UseTPM12Encoding()
2222
}
2323

2424
// Supported TPM commands.

tpm2/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
)
2727

2828
func init() {
29-
tpmutil.UseTPM20LengthPrefixSize()
29+
tpmutil.UseTPM20Encoding()
3030
}
3131

3232
// MAX_DIGEST_BUFFER is the maximum size of []byte request or response fields.

tpmutil/encoding.go

Lines changed: 86 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,49 @@ import (
2323
"reflect"
2424
)
2525

26-
// lengthPrefixSize is the size in bytes of length prefix for byte slices.
27-
//
28-
// In TPM 1.2 this is 4 bytes.
29-
// In TPM 2.0 this is 2 bytes.
30-
var lengthPrefixSize int
26+
// Encoding implements encoding logic for different versions of the TPM
27+
// specification.
28+
type Encoding struct {
29+
// lengthPrefixSize is the size in bytes of length prefix for byte slices.
30+
//
31+
// In TPM 1.2 this is 4 bytes.
32+
// In TPM 2.0 this is 2 bytes.
33+
lengthPrefixSize int
34+
}
35+
36+
var (
37+
// Encoding1_2 implements TPM 1.2 encoding.
38+
Encoding1_2 = &Encoding{
39+
lengthPrefixSize: tpm12PrefixSize,
40+
}
41+
// Encoding2_0 implements TPM 2.0 encoding.
42+
Encoding2_0 = &Encoding{
43+
lengthPrefixSize: tpm20PrefixSize,
44+
}
45+
46+
defaultEncoding *Encoding
47+
)
3148

3249
const (
3350
tpm12PrefixSize = 4
3451
tpm20PrefixSize = 2
3552
)
3653

37-
// UseTPM12LengthPrefixSize makes Pack/Unpack use TPM 1.2 encoding for byte
38-
// arrays.
39-
func UseTPM12LengthPrefixSize() {
40-
lengthPrefixSize = tpm12PrefixSize
54+
// UseTPM12Encoding makes the package level Pack/Unpack functions use
55+
// TPM 1.2 encoding for byte arrays.
56+
func UseTPM12Encoding() {
57+
defaultEncoding = Encoding1_2
4158
}
4259

43-
// UseTPM20LengthPrefixSize makes Pack/Unpack use TPM 2.0 encoding for byte
44-
// arrays.
45-
func UseTPM20LengthPrefixSize() {
46-
lengthPrefixSize = tpm20PrefixSize
60+
// UseTPM20Encoding makes the package level Pack/Unpack functions use
61+
// TPM 2.0 encoding for byte arrays.
62+
func UseTPM20Encoding() {
63+
defaultEncoding = Encoding2_0
4764
}
4865

4966
// packedSize computes the size of a sequence of types that can be passed to
5067
// binary.Read or binary.Write.
51-
func packedSize(elts ...interface{}) (int, error) {
68+
func (enc *Encoding) packedSize(elts ...interface{}) (int, error) {
5269
var size int
5370
for _, e := range elts {
5471
marshaler, ok := e.(SelfMarshaler)
@@ -59,15 +76,15 @@ func packedSize(elts ...interface{}) (int, error) {
5976
v := reflect.ValueOf(e)
6077
switch v.Kind() {
6178
case reflect.Ptr:
62-
s, err := packedSize(reflect.Indirect(v).Interface())
79+
s, err := enc.packedSize(reflect.Indirect(v).Interface())
6380
if err != nil {
6481
return 0, err
6582
}
6683

6784
size += s
6885
case reflect.Struct:
6986
for i := 0; i < v.NumField(); i++ {
70-
s, err := packedSize(v.Field(i).Interface())
87+
s, err := enc.packedSize(v.Field(i).Interface())
7188
if err != nil {
7289
return 0, err
7390
}
@@ -77,7 +94,7 @@ func packedSize(elts ...interface{}) (int, error) {
7794
case reflect.Slice:
7895
switch s := e.(type) {
7996
case []byte:
80-
size += lengthPrefixSize + len(s)
97+
size += enc.lengthPrefixSize + len(s)
8198
case RawBytes:
8299
size += len(s)
83100
default:
@@ -100,16 +117,27 @@ func packedSize(elts ...interface{}) (int, error) {
100117
// fixed length or slices of fixed-length types and packs them into a single
101118
// byte array using binary.Write. It updates the CommandHeader to have the right
102119
// length.
103-
func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
120+
func (enc *Encoding) packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
104121
hdrSize := binary.Size(ch)
105-
bodySize, err := packedSize(cmd...)
122+
bodySize, err := enc.packedSize(cmd...)
106123
if err != nil {
107124
return nil, fmt.Errorf("couldn't compute packed size for message body: %v", err)
108125
}
109126
ch.Size = uint32(hdrSize + bodySize)
110127
in := []interface{}{ch}
111128
in = append(in, cmd...)
112-
return Pack(in...)
129+
return enc.Pack(in...)
130+
}
131+
132+
// Pack encodes a set of elements using the package's default encoding.
133+
//
134+
// Callers must call UseTPM12Encoding() or UseTPM20Encoding() before calling
135+
// this method.
136+
func Pack(elts ...interface{}) ([]byte, error) {
137+
if defaultEncoding == nil {
138+
return nil, errors.New("default encoding not initialized")
139+
}
140+
return defaultEncoding.Pack(elts...)
113141
}
114142

115143
// Pack encodes a set of elements into a single byte array, using
@@ -119,13 +147,9 @@ func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
119147
// It has one difference from encoding/binary: it encodes byte slices with a
120148
// prepended length, to match how the TPM encodes variable-length arrays. If
121149
// you wish to add a byte slice without length prefix, use RawBytes.
122-
func Pack(elts ...interface{}) ([]byte, error) {
123-
if lengthPrefixSize == 0 {
124-
return nil, errors.New("lengthPrefixSize must be initialized")
125-
}
126-
150+
func (enc *Encoding) Pack(elts ...interface{}) ([]byte, error) {
127151
buf := new(bytes.Buffer)
128-
if err := packType(buf, elts...); err != nil {
152+
if err := enc.packType(buf, elts...); err != nil {
129153
return nil, err
130154
}
131155

@@ -137,7 +161,7 @@ func Pack(elts ...interface{}) ([]byte, error) {
137161
// lengthPrefixSize size followed by the bytes. The function unpackType
138162
// performs the inverse operation of unpacking slices stored in this manner and
139163
// using encoding/binary for everything else.
140-
func packType(buf io.Writer, elts ...interface{}) error {
164+
func (enc *Encoding) packType(buf io.Writer, elts ...interface{}) error {
141165
for _, e := range elts {
142166
marshaler, ok := e.(SelfMarshaler)
143167
if ok {
@@ -149,20 +173,20 @@ func packType(buf io.Writer, elts ...interface{}) error {
149173
v := reflect.ValueOf(e)
150174
switch v.Kind() {
151175
case reflect.Ptr:
152-
if err := packType(buf, reflect.Indirect(v).Interface()); err != nil {
176+
if err := enc.packType(buf, reflect.Indirect(v).Interface()); err != nil {
153177
return err
154178
}
155179
case reflect.Struct:
156180
// TODO(awly): Currently packType cannot handle non-struct fields that implement SelfMarshaler
157181
for i := 0; i < v.NumField(); i++ {
158-
if err := packType(buf, v.Field(i).Interface()); err != nil {
182+
if err := enc.packType(buf, v.Field(i).Interface()); err != nil {
159183
return err
160184
}
161185
}
162186
case reflect.Slice:
163187
switch s := e.(type) {
164188
case []byte:
165-
switch lengthPrefixSize {
189+
switch enc.lengthPrefixSize {
166190
case tpm20PrefixSize:
167191
if err := binary.Write(buf, binary.BigEndian, uint16(len(s))); err != nil {
168192
return err
@@ -172,7 +196,7 @@ func packType(buf io.Writer, elts ...interface{}) error {
172196
return err
173197
}
174198
default:
175-
return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", lengthPrefixSize)
199+
return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", enc.lengthPrefixSize)
176200
}
177201
if err := binary.Write(buf, binary.BigEndian, s); err != nil {
178202
return err
@@ -195,21 +219,45 @@ func packType(buf io.Writer, elts ...interface{}) error {
195219
return nil
196220
}
197221

222+
// Unpack is a convenience wrapper around UnpackBuf using the package's default
223+
// encoding.
224+
//
225+
// Callers must call UseTPM12Encoding() or UseTPM20Encoding() before calling
226+
// this method.
227+
func Unpack(b []byte, elts ...interface{}) (int, error) {
228+
if defaultEncoding == nil {
229+
return 0, errors.New("default encoding not initialized")
230+
}
231+
return defaultEncoding.Unpack(b, elts...)
232+
}
233+
198234
// Unpack is a convenience wrapper around UnpackBuf. Unpack returns the number
199235
// of bytes read from b to fill elts and error, if any.
200-
func Unpack(b []byte, elts ...interface{}) (int, error) {
236+
func (enc *Encoding) Unpack(b []byte, elts ...interface{}) (int, error) {
201237
buf := bytes.NewBuffer(b)
202-
err := UnpackBuf(buf, elts...)
238+
err := enc.UnpackBuf(buf, elts...)
203239
read := len(b) - buf.Len()
204240
return read, err
205241
}
206242

243+
// UnpackBuf recursively unpacks types from a reader using the package's default
244+
// encoding.
245+
//
246+
// Callers must call UseTPM12Encoding() or UseTPM20Encoding() before calling
247+
// this method.
248+
func UnpackBuf(buf io.Reader, elts ...interface{}) error {
249+
if defaultEncoding == nil {
250+
return errors.New("default encoding not initialized")
251+
}
252+
return defaultEncoding.UnpackBuf(buf, elts...)
253+
}
254+
207255
// UnpackBuf recursively unpacks types from a reader just as encoding/binary
208256
// does under binary.BigEndian, but with one difference: it unpacks a byte
209257
// slice by first reading an integer with lengthPrefixSize bytes, then reading
210258
// that many bytes. It assumes that incoming values are pointers to values so
211259
// that, e.g., underlying slices can be resized as needed.
212-
func UnpackBuf(buf io.Reader, elts ...interface{}) error {
260+
func (enc *Encoding) UnpackBuf(buf io.Reader, elts ...interface{}) error {
213261
for _, e := range elts {
214262
v := reflect.ValueOf(e)
215263
k := v.Kind()
@@ -233,7 +281,7 @@ func UnpackBuf(buf io.Reader, elts ...interface{}) error {
233281
case reflect.Struct:
234282
// Decompose the struct and copy over the values.
235283
for i := 0; i < iv.NumField(); i++ {
236-
if err := UnpackBuf(buf, iv.Field(i).Addr().Interface()); err != nil {
284+
if err := enc.UnpackBuf(buf, iv.Field(i).Addr().Interface()); err != nil {
237285
return err
238286
}
239287
}
@@ -250,21 +298,21 @@ func UnpackBuf(buf io.Reader, elts ...interface{}) error {
250298
}
251299
size = int(tmpSize)
252300
// TPM 2.0
253-
case lengthPrefixSize == tpm20PrefixSize:
301+
case enc.lengthPrefixSize == tpm20PrefixSize:
254302
var tmpSize uint16
255303
if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
256304
return err
257305
}
258306
size = int(tmpSize)
259307
// TPM 1.2
260-
case lengthPrefixSize == tpm12PrefixSize:
308+
case enc.lengthPrefixSize == tpm12PrefixSize:
261309
var tmpSize uint32
262310
if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
263311
return err
264312
}
265313
size = int(tmpSize)
266314
default:
267-
return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", lengthPrefixSize)
315+
return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", enc.lengthPrefixSize)
268316
}
269317

270318
// A zero size is used by the TPM to signal that certain elements

0 commit comments

Comments
 (0)