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