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