-
Notifications
You must be signed in to change notification settings - Fork 159
/
encoding.go
211 lines (191 loc) · 6.51 KB
/
encoding.go
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright (c) 2018, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tpmutil
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"reflect"
)
var (
selfMarshalerType = reflect.TypeOf((*SelfMarshaler)(nil)).Elem()
handlesAreaType = reflect.TypeOf((*[]Handle)(nil))
)
// packWithHeader takes a header and a sequence of elements that are either of
// fixed length or slices of fixed-length types and packs them into a single
// byte array using binary.Write. It updates the CommandHeader to have the right
// length.
func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
hdrSize := binary.Size(ch)
body, err := Pack(cmd...)
if err != nil {
return nil, fmt.Errorf("couldn't pack message body: %v", err)
}
bodySize := len(body)
ch.Size = uint32(hdrSize + bodySize)
header, err := Pack(ch)
if err != nil {
return nil, fmt.Errorf("couldn't pack message header: %v", err)
}
return append(header, body...), nil
}
// Pack encodes a set of elements into a single byte array, using
// encoding/binary. This means that all the elements must be encodeable
// according to the rules of encoding/binary.
//
// It has one difference from encoding/binary: it encodes byte slices with a
// prepended length, to match how the TPM encodes variable-length arrays. If
// you wish to add a byte slice without length prefix, use RawBytes.
func Pack(elts ...interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
if err := packType(buf, elts...); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// tryMarshal attempts to use a TPMMarshal() method defined on the type
// to pack v into buf. True is returned if the method exists and the
// marshal was attempted.
func tryMarshal(buf io.Writer, v reflect.Value) (bool, error) {
t := v.Type()
if t.Implements(selfMarshalerType) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return true, fmt.Errorf("cannot call TPMMarshal on a nil pointer of type %T", v)
}
return true, v.Interface().(SelfMarshaler).TPMMarshal(buf)
}
// We might have a non-pointer struct field, but we dont have a
// pointer with which to implement the interface.
// If the pointer of the type implements the interface, we should be
// able to construct a value to call TPMMarshal() with.
// TODO(awly): Try and avoid blowing away private data by using Addr() instead of Set()
if reflect.PtrTo(t).Implements(selfMarshalerType) {
tmp := reflect.New(t)
tmp.Elem().Set(v)
return true, tmp.Interface().(SelfMarshaler).TPMMarshal(buf)
}
return false, nil
}
func packValue(buf io.Writer, v reflect.Value) error {
if v.Type() == handlesAreaType {
v = v.Convert(reflect.TypeOf((*handleList)(nil)))
}
if canMarshal, err := tryMarshal(buf, v); canMarshal {
return err
}
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
return fmt.Errorf("cannot pack nil %s", v.Type().String())
}
return packValue(buf, v.Elem())
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if err := packValue(buf, f); err != nil {
return err
}
}
default:
return binary.Write(buf, binary.BigEndian, v.Interface())
}
return nil
}
func packType(buf io.Writer, elts ...interface{}) error {
for _, e := range elts {
if err := packValue(buf, reflect.ValueOf(e)); err != nil {
return err
}
}
return nil
}
// tryUnmarshal attempts to use TPMUnmarshal() to perform the
// unpack, if the given value implements SelfMarshaler.
// True is returned if v implements SelfMarshaler & TPMUnmarshal
// was called, along with an error returned from TPMUnmarshal.
func tryUnmarshal(buf io.Reader, v reflect.Value) (bool, error) {
t := v.Type()
if t.Implements(selfMarshalerType) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return true, fmt.Errorf("cannot call TPMUnmarshal on a nil pointer")
}
return true, v.Interface().(SelfMarshaler).TPMUnmarshal(buf)
}
// We might have a non-pointer struct field, which is addressable,
// If the pointer of the type implements the interface, and the
// value is addressable, we should be able to call TPMUnmarshal().
if v.CanAddr() && reflect.PtrTo(t).Implements(selfMarshalerType) {
return true, v.Addr().Interface().(SelfMarshaler).TPMUnmarshal(buf)
}
return false, nil
}
// Unpack is a convenience wrapper around UnpackBuf. Unpack returns the number
// of bytes read from b to fill elts and error, if any.
func Unpack(b []byte, elts ...interface{}) (int, error) {
buf := bytes.NewBuffer(b)
err := UnpackBuf(buf, elts...)
read := len(b) - buf.Len()
return read, err
}
func unpackValue(buf io.Reader, v reflect.Value) error {
if v.Type() == handlesAreaType {
v = v.Convert(reflect.TypeOf((*handleList)(nil)))
}
if didUnmarshal, err := tryUnmarshal(buf, v); didUnmarshal {
return err
}
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
return fmt.Errorf("cannot unpack nil %s", v.Type().String())
}
return unpackValue(buf, v.Elem())
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if err := unpackValue(buf, f); err != nil {
return err
}
}
return nil
default:
// binary.Read can only set pointer values, so we need to take the address.
if !v.CanAddr() {
return fmt.Errorf("cannot unpack unaddressable leaf type %q", v.Type().String())
}
return binary.Read(buf, binary.BigEndian, v.Addr().Interface())
}
}
// UnpackBuf recursively unpacks types from a reader just as encoding/binary
// does under binary.BigEndian, but with one difference: it unpacks a byte
// slice by first reading an integer with lengthPrefixSize bytes, then reading
// that many bytes. It assumes that incoming values are pointers to values so
// that, e.g., underlying slices can be resized as needed.
func UnpackBuf(buf io.Reader, elts ...interface{}) error {
for _, e := range elts {
v := reflect.ValueOf(e)
if v.Kind() != reflect.Ptr {
return fmt.Errorf("non-pointer value %q passed to UnpackBuf", v.Type().String())
}
if v.IsNil() {
return errors.New("nil pointer passed to UnpackBuf")
}
if err := unpackValue(buf, v); err != nil {
return err
}
}
return nil
}