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 }