github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+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  	"fmt"
    12  	"io"
    13  	"log"
    14  
    15  	"github.com/google/go-tpm/tpm2"
    16  	"github.com/google/go-tpm/tpmutil"
    17  	slaunch "github.com/u-root/u-root/pkg/securelaunch"
    18  )
    19  
    20  /*
    21   * tpm2.ReadPCR and tpm2.ExtendPCR need hashAlgo passed.
    22   * using sha256 for now
    23   */
    24  const (
    25  	hashAlgo = tpm2.AlgSHA256
    26  )
    27  
    28  /*
    29   * hashReader calculates the sha256 sum of an io reader.
    30   */
    31  func hashReader(f io.Reader) []byte {
    32  
    33  	h := sha256.New()
    34  	if _, err := io.Copy(h, f); err != nil {
    35  		log.Fatal(err)
    36  	}
    37  
    38  	return h.Sum(nil)
    39  }
    40  
    41  /*
    42   * GetHandle returns a tpm device handle from go-tpm/tpm2
    43   * returns a tpm handle from go-tpm/tpm2
    44   * that can be used for storing hashes.
    45   */
    46  func GetHandle() (io.ReadWriteCloser, error) {
    47  	tpm2, err := tpm2.OpenTPM("/dev/tpm0")
    48  	if err != nil {
    49  		return nil, fmt.Errorf("couldn't talk to TPM Device: err=%v", err)
    50  	}
    51  
    52  	return tpm2, nil
    53  }
    54  
    55  /*
    56   * ReadPCR reads pcr#x, where x is provided by 'pcr' arg and returns
    57   * the result in a byte slice.
    58   * 'tpmHandle' is the tpm device that owns the 'pcr'.
    59   * err is returned if read fails.
    60   */
    61  func ReadPCR(tpmHandle io.ReadWriteCloser, pcr int) ([]byte, error) {
    62  	val, err := tpm2.ReadPCR(tpmHandle, pcr, hashAlgo)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("Can't read PCR %d, err= %v", pcr, err)
    65  	}
    66  	return val, nil
    67  }
    68  
    69  /*
    70   * ExtendPCR writes the measurements passed as 'hash' arg to pcr#x,
    71   * where x is provided by 'pcr' arg.
    72   *
    73   * pcr is owned by 'tpm2Handle', a tpm device handle.
    74   * err is returned if write to pcr fails.
    75   */
    76  func ExtendPCR(tpmHandle io.ReadWriteCloser, pcr int, hash []byte) error {
    77  	return tpm2.PCRExtend(tpmHandle, tpmutil.Handle(pcr), hashAlgo, hash, "")
    78  }
    79  
    80  /*
    81   * ExtendPCRDebug extends a PCR with the contents of a byte slice.
    82   *
    83   * In debug mode, it prints
    84   * 1. old pcr value before the hash is written to pcr
    85   * 2. new pcr values after hash is written to pcr
    86   * 3. compares old and new pcr values and prints error if they are not
    87   */
    88  func ExtendPCRDebug(tpmHandle io.ReadWriteCloser, pcr int, data io.Reader) error {
    89  	oldPCRValue, err := ReadPCR(tpmHandle, pcr)
    90  	if err != nil {
    91  		return fmt.Errorf("ReadPCR failed, err=%v", err)
    92  	}
    93  	slaunch.Debug("ExtendPCRDebug: oldPCRValue = [%x]", oldPCRValue)
    94  
    95  	hash := hashReader(data)
    96  
    97  	slaunch.Debug("Adding hash=[%x] to PCR #%d", hash, pcr)
    98  	if e := ExtendPCR(tpmHandle, pcr, hash); e != nil {
    99  		return fmt.Errorf("Can't extend PCR %d, err=%v", pcr, e)
   100  	}
   101  
   102  	newPCRValue, err := ReadPCR(tpmHandle, pcr)
   103  	if err != nil {
   104  		return fmt.Errorf("ReadPCR failed, err=%v", err)
   105  	}
   106  	slaunch.Debug("ExtendPCRDebug: newPCRValue = [%x]", newPCRValue)
   107  
   108  	finalPCR := hashReader(bytes.NewReader(append(oldPCRValue, hash...)))
   109  	if !bytes.Equal(finalPCR, newPCRValue) {
   110  		return fmt.Errorf("PCRs not equal, got %x, want %x", finalPCR, newPCRValue)
   111  	}
   112  
   113  	return nil
   114  }