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