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 }