@@ -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
3249const (
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