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 }