github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tpm2/encoding.go (about) 1 // Copyright (c) 2014, Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tpm2 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "errors" 21 "io" 22 "reflect" 23 ) 24 25 // Make commandHeader 26 func MakeCommandHeader(tag uint16, size uint32, command uint32) (commandHeader, error) { 27 var cmdHdr commandHeader 28 cmdHdr.Tag = tag 29 cmdHdr.Size = size + 10 30 cmdHdr.Cmd = command 31 return cmdHdr, nil 32 } 33 34 // Decode response 35 func DecodeCommandResponse(in []byte) (uint16, uint32, TpmError, error) { 36 var tag uint16 37 var size uint32 38 var status uint32 39 40 out := []interface{}{&tag, &size, &status} 41 err := unpack(in, out) 42 if err != nil { 43 return 0, 0, 0, errors.New("Can't decode response") 44 } 45 46 return tag, size, TpmError(status), nil 47 } 48 49 // packedSize computes the size of a sequence of types that can be passed to 50 // binary.Read or binary.Write. 51 func packedSize(elts []interface{}) int { 52 var size int 53 for _, e := range elts { 54 v := reflect.ValueOf(e) 55 switch v.Kind() { 56 case reflect.Ptr: 57 s := packedSize([]interface{}{reflect.Indirect(v).Interface()}) 58 if s < 0 { 59 return s 60 } 61 62 size += s 63 case reflect.Struct: 64 for i := 0; i < v.NumField(); i++ { 65 s := packedSize([]interface{}{v.Field(i).Interface()}) 66 if s < 0 { 67 return s 68 } 69 70 size += s 71 } 72 case reflect.Slice: 73 b, ok := e.([]byte) 74 if !ok { 75 return -1 76 } 77 78 size += 2 + len(b) 79 default: 80 s := binary.Size(e) 81 if s < 0 { 82 return s 83 } 84 85 size += s 86 } 87 } 88 89 return size 90 } 91 92 // packWithBytes takes a command and byte slice and packs them into a single 93 // nil is error 94 func packWithBytes(ch commandHeader, args []byte) ([]byte) { 95 hdrSize := binary.Size(ch) 96 bodySize := len(args) 97 if bodySize < 0 { 98 return nil 99 } 100 ch.Size = uint32(hdrSize + bodySize) 101 cmdHdr, _ := pack([]interface{}{ch}) 102 cmd := append(cmdHdr, args...) 103 return cmd 104 } 105 106 // packWithHeader takes a header and a sequence of elements that are either of 107 // fixed length or slices of fixed-length types and packs them into a single 108 // byte array using binary.Write. It updates the CommandHeader to have the right 109 // length. 110 func packWithHeader(ch commandHeader, cmd []interface{}) ([]byte, error) { 111 hdrSize := binary.Size(ch) 112 bodySize := packedSize(cmd) 113 if bodySize < 0 { 114 return nil, errors.New("couldn't compute packed size for message body") 115 } 116 ch.Size = uint32(hdrSize + bodySize) 117 in := []interface{}{ch} 118 in = append(in, cmd...) 119 return pack(in) 120 } 121 122 // pack encodes a set of elements into a single byte array, using 123 // encoding/binary. This means that all the elements must be encodeable 124 // according to the rules of encoding/binary. It has one difference from 125 // encoding/binary: it encodes byte slices with a prepended uint16 length, to 126 // match how the TPM encodes variable-length arrays. 127 func pack(elts []interface{}) ([]byte, error) { 128 buf := new(bytes.Buffer) 129 if err := packType(buf, elts); err != nil { 130 return nil, err 131 } 132 133 return buf.Bytes(), nil 134 } 135 136 // packType recursively packs types the same way that encoding/binary does under 137 // binary.BigEndian, but with one difference: it packs a byte slice as a uint16 138 // size followed by the bytes. The function unpackType performs the inverse 139 // operation of unpacking slices stored in this manner and using encoding/binary 140 // for everything else. 141 func packType(buf io.Writer, elts []interface{}) error { 142 for _, e := range elts { 143 v := reflect.ValueOf(e) 144 switch v.Kind() { 145 case reflect.Ptr: 146 if err := packType(buf, []interface{}{reflect.Indirect(v).Interface()}); err != nil { 147 return err 148 } 149 case reflect.Struct: 150 for i := 0; i < v.NumField(); i++ { 151 if err := packType(buf, []interface{}{v.Field(i).Interface()}); err != nil { 152 return err 153 } 154 } 155 case reflect.Slice: 156 b, ok := e.([]byte) 157 if !ok { 158 return errors.New("can't pack slices of non-byte values") 159 } 160 161 if err := binary.Write(buf, binary.BigEndian, uint16(len(b))); err != nil { 162 return err 163 } 164 165 if err := binary.Write(buf, binary.BigEndian, b); err != nil { 166 return err 167 } 168 default: 169 if err := binary.Write(buf, binary.BigEndian, e); err != nil { 170 return err 171 } 172 } 173 174 } 175 176 return nil 177 } 178 179 // unpack performs the inverse operation from pack. 180 func unpack(b []byte, elts []interface{}) error { 181 buf := bytes.NewBuffer(b) 182 return unpackType(buf, elts) 183 } 184 185 // resizeBytes changes the size of the byte slice according to the second param. 186 func resizeBytes(b *[]byte, size uint32) { 187 // Append to the slice if it's too small and shrink it if it's too large. 188 l := len(*b) 189 ss := int(size) 190 if l > ss { 191 *b = (*b)[:ss] 192 } else if l < ss { 193 *b = append(*b, make([]byte, ss-l)...) 194 } 195 } 196 197 // unpackType recursively unpacks types from a reader just as encoding/binary 198 // does under binary.BigEndian, but with one difference: it unpacks a byte slice 199 // by first reading a uint16, then reading that many bytes. It assumes that 200 // incoming values are pointers to values so that, e.g., underlying slices can 201 // be resized as needed. 202 func unpackType(buf io.Reader, elts []interface{}) error { 203 for _, e := range elts { 204 v := reflect.ValueOf(e) 205 k := v.Kind() 206 if k != reflect.Ptr { 207 return errors.New("all values passed to unpack must be pointers") 208 } 209 210 if v.IsNil() { 211 return errors.New("can't fill a nil pointer") 212 } 213 214 iv := reflect.Indirect(v) 215 switch iv.Kind() { 216 case reflect.Struct: 217 // Decompose the struct and copy over the values. 218 for i := 0; i < iv.NumField(); i++ { 219 if err := unpackType(buf, []interface{}{iv.Field(i).Addr().Interface()}); err != nil { 220 return err 221 } 222 } 223 case reflect.Slice: 224 // Read a uint16 and resize the byte array as needed 225 var size uint16 226 if err := binary.Read(buf, binary.BigEndian, &size); err != nil { 227 return err 228 } 229 230 // A zero size is used by the TPM to signal that certain elements 231 // are not present. 232 if size == 0 { 233 continue 234 } 235 236 b, ok := e.(*[]byte) 237 if !ok { 238 return errors.New("can't fill pointers to slices of non-byte values") 239 } 240 241 resizeBytes(b, uint32(size)) 242 if err := binary.Read(buf, binary.BigEndian, e); err != nil { 243 return err 244 } 245 default: 246 if err := binary.Read(buf, binary.BigEndian, e); err != nil { 247 return err 248 } 249 } 250 251 } 252 253 return nil 254 }