github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/securelaunch/tpm/tpm.go (about)

     1  // Copyright 2019 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package tpm reads and extends pcrs with measurements.
     6  package tpm
     7  
     8  import (
     9  	"bytes"
    10  	"crypto/sha256"
    11  	"encoding/binary"
    12  	"errors"
    13  	"fmt"
    14  	"io"
    15  	"log"
    16  
    17  	"github.com/google/go-tpm/tpm2"
    18  	slaunch "github.com/u-root/u-root/pkg/securelaunch"
    19  	"github.com/u-root/u-root/pkg/securelaunch/eventlog"
    20  	"github.com/u-root/u-root/pkg/tss"
    21  )
    22  
    23  var hashAlgo = tpm2.AlgSHA256
    24  var tpmHandle *tss.TPM
    25  
    26  // marshalPcrEvent writes structure fields piecemeal to buffer.
    27  func marshalPcrEvent(pcr uint32, h []byte, eventDesc []byte) ([]byte, error) {
    28  
    29  	const baseTypeTXT = 0x400                       // TXT specification base event value for DRTM values
    30  	const slaunchType = uint32(baseTypeTXT + 0x102) // Secure Launch event log entry type.
    31  	count := uint32(1)
    32  	eventDescLen := uint32(len(eventDesc))
    33  	slaunch.Debug("marshalPcrEvent: pcr=[%v], slaunchType=[%v], count=[%v], hashAlgo=[%v], eventDesc=[%s], eventDescLen=[%v]",
    34  		pcr, slaunchType, count, hashAlgo, eventDesc, eventDescLen)
    35  
    36  	endianess := binary.LittleEndian
    37  	var buf bytes.Buffer
    38  
    39  	if err := binary.Write(&buf, endianess, pcr); err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	if err := binary.Write(&buf, endianess, slaunchType); err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	if err := binary.Write(&buf, endianess, count); err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	for i := uint32(0); i < count; i++ {
    52  		if err := binary.Write(&buf, endianess, hashAlgo); err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		if err := binary.Write(&buf, endianess, h); err != nil {
    57  			return nil, err
    58  		}
    59  	}
    60  
    61  	if err := binary.Write(&buf, endianess, eventDescLen); err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	if err := binary.Write(&buf, endianess, eventDesc); err != nil {
    66  		return nil, err
    67  	}
    68  	return buf.Bytes(), nil
    69  }
    70  
    71  // sendEventToSysfs marshals measurement events and writes them to sysfs.
    72  func sendEventToSysfs(pcr uint32, h []byte, eventDesc []byte) {
    73  
    74  	b, err := marshalPcrEvent(pcr, h, eventDesc)
    75  	if err != nil {
    76  		log.Println(err)
    77  	}
    78  
    79  	if e := eventlog.Add(b); e != nil {
    80  		log.Println(e)
    81  	}
    82  }
    83  
    84  /*
    85   * hashReader calculates the sha256 sum of an io reader.
    86   */
    87  func hashReader(f io.Reader) []byte {
    88  
    89  	h := sha256.New()
    90  	if _, err := io.Copy(h, f); err != nil {
    91  		log.Fatal(err)
    92  	}
    93  
    94  	return h.Sum(nil)
    95  }
    96  
    97  /*
    98   * New sets up a tpm device handle
    99   * that can be used for storing hashes.
   100   */
   101  func New() error {
   102  	tpm, err := tss.NewTPM()
   103  	if err != nil {
   104  		return fmt.Errorf("couldn't talk to TPM Device: err=%v", err)
   105  	}
   106  
   107  	tpmHandle = tpm
   108  	return nil
   109  }
   110  
   111  /*
   112   * Close ends connection to a tpm device handle
   113   */
   114  func Close() {
   115  	if tpmHandle != nil {
   116  		tpmHandle.Close()
   117  		tpmHandle = nil
   118  	}
   119  }
   120  
   121  /*
   122   * readPCR reads pcr#x, where x is provided by 'pcr' arg and returns
   123   * the result in a byte slice.
   124   * 'tpmHandle' is the tpm device that owns the 'pcr'.
   125   * err is returned if read fails.
   126   */
   127  func readPCR(pcr uint32) ([]byte, error) {
   128  	if tpmHandle == nil {
   129  		return nil, errors.New("tpmHandle is nil")
   130  	}
   131  
   132  	val, err := tpmHandle.ReadPCR(pcr)
   133  	if err != nil {
   134  		return nil, fmt.Errorf("can't read PCR %d, err= %v", pcr, err)
   135  	}
   136  	return val, nil
   137  }
   138  
   139  /*
   140   * extendPCR writes the measurements passed as 'hash' arg to pcr#x,
   141   * where x is provided by 'pcr' arg.
   142   *
   143   * pcr is owned by 'tpm2Handle', a tpm device handle.
   144   * err is returned if write to pcr fails.
   145   */
   146  func extendPCR(pcr uint32, hash []byte) error {
   147  	if tpmHandle == nil {
   148  		return errors.New("tpmHandle is nil")
   149  	}
   150  
   151  	return tpmHandle.Extend(hash, pcr)
   152  }
   153  
   154  /*
   155   * ExtendPCRDebug extends a PCR with the contents of a byte slice
   156   * and notifies the kernel of this measurement by sending event via sysfs.
   157   *
   158   * In debug mode, it prints
   159   * 1. old pcr value before the hash is written to pcr
   160   * 2. new pcr values after hash is written to pcr
   161   * 3. compares old and new pcr values and prints error if they are not
   162   */
   163  func ExtendPCRDebug(pcr uint32, data io.Reader, eventDesc string) error {
   164  	oldPCRValue, err := readPCR(pcr)
   165  	if err != nil {
   166  		return fmt.Errorf("readPCR failed, err=%v", err)
   167  	}
   168  	slaunch.Debug("ExtendPCRDebug: oldPCRValue = [%x]", oldPCRValue)
   169  
   170  	hash := hashReader(data)
   171  
   172  	slaunch.Debug("Adding hash=[%x] to PCR #%d", hash, pcr)
   173  	if e := extendPCR(pcr, hash); e != nil {
   174  		return fmt.Errorf("can't extend PCR %d, err=%v", pcr, e)
   175  	}
   176  	slaunch.Debug(eventDesc)
   177  
   178  	// send event if PCR was successfully extended above.
   179  	sendEventToSysfs(pcr, hash, []byte(eventDesc))
   180  
   181  	newPCRValue, err := readPCR(pcr)
   182  	if err != nil {
   183  		return fmt.Errorf("readPCR failed, err=%v", err)
   184  	}
   185  	slaunch.Debug("ExtendPCRDebug: newPCRValue = [%x]", newPCRValue)
   186  
   187  	finalPCR := hashReader(bytes.NewReader(append(oldPCRValue, hash...)))
   188  	if !bytes.Equal(finalPCR, newPCRValue) {
   189  		return fmt.Errorf("PCRs not equal, got %x, want %x", finalPCR, newPCRValue)
   190  	}
   191  
   192  	return nil
   193  }