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  }