github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/txtlog/txtlog.go (about) 1 // Copyright 2020 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 txtlog provides reading/parsing of Intel TXT logs. 6 // Huge parts were taken from 9elements/tpmtool 7 package txtlog 8 9 import ( 10 "bytes" 11 "encoding/binary" 12 "errors" 13 "fmt" 14 "io" 15 "os" 16 "unicode/utf16" 17 18 tss "github.com/u-root/u-root/pkg/tss" 19 ) 20 21 /* 22 [1] TCG EFI Platform Specification For TPM Family 1.1 or 1.2 23 https://trustedcomputinggroup.org/wp-content/uploads/TCG_EFI_Platform_1_22_Final_-v15.pdf 24 25 [2] TCG PC Client Specific Implementation Specification for Conventional BIOS", version 1.21 26 https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientImplementation_1-21_1_00.pdf 27 28 [3] TCG EFI Protocol Specification, Family "2.0" 29 https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf 30 31 [4] TCG PC Client Platform Firmware Profile Specification 32 https://trustedcomputinggroup.org/wp-content/uploads/PC-ClientSpecific_Platform_Profile_for_TPM_2p0_Systems_v51.pdf 33 */ 34 var ( 35 // DefaultTCPABinaryLog log file where the TCPA log is stored 36 DefaultTCPABinaryLog = "/sys/kernel/security/tpm0/binary_bios_measurements" 37 ) 38 39 var HashAlgoToSize = map[IAlgHash]IAlgHashSize{ 40 TPMAlgSha: TPMAlgShaSize, 41 TPMAlgSha256: TPMAlgSha256Size, 42 TPMAlgSha384: TPMAlgSha384Size, 43 TPMAlgSha512: TPMAlgSha512Size, 44 TPMAlgSm3s256: TPMAlgSm3s256Size, 45 } 46 47 func ParseLog(firmware FirmwareType, tpmSpec tss.TPMVersion) (*PCRLog, error) { 48 var pcrLog *PCRLog 49 var err error 50 51 switch tpmSpec { 52 case tss.TPMVersion12: 53 pcrLog, err = readTPM1Log(firmware) 54 if err != nil { 55 return nil, err 56 } 57 case tss.TPMVersion20: 58 pcrLog, err = readTPM2Log(firmware) 59 if err != nil { 60 // Kernel eventlog workaround does not export agile measurement log.. 61 pcrLog, err = readTPM1Log(firmware) 62 if err != nil { 63 return nil, err 64 } 65 } 66 default: 67 return nil, errors.New("No valid TPM specification found") 68 } 69 70 return pcrLog, nil 71 } 72 73 func DumpLog(tcpaLog *PCRLog) error { 74 for _, pcr := range tcpaLog.PcrList { 75 fmt.Printf("%s\n", pcr) 76 77 fmt.Println() 78 } 79 80 return nil 81 } 82 83 func readTPM1Log(firmware FirmwareType) (*PCRLog, error) { 84 var pcrLog PCRLog 85 86 file, err := os.Open(DefaultTCPABinaryLog) 87 if err != nil { 88 return nil, err 89 } 90 defer file.Close() 91 92 pcrLog.Firmware = firmware 93 94 if firmware == "TXT" { 95 var pcrLog PCRLog 96 97 container, err := readTxtEventLogContainer(file) 98 if err != nil { 99 return nil, err 100 } 101 102 // seek to first PCR event 103 if _, err := file.Seek(int64(container.PcrEventsOffset), io.SeekStart); err != nil { 104 return nil, err 105 } 106 107 for { 108 offset, err := file.Seek(0, io.SeekCurrent) 109 if err != nil { 110 return nil, err 111 } 112 113 if offset >= int64(container.NextEventOffset) { 114 break 115 } 116 117 pcrEvent, err := parseTcgPcrEvent(file) 118 if err != nil { 119 // NB: error out even for EOF because it should 120 // not be seen before NextEventOffset 121 return nil, err 122 } 123 124 pcrLog.PcrList = append(pcrLog.PcrList, pcrEvent) 125 } 126 } else { 127 for { 128 pcrEvent, err := parseTcgPcrEvent(file) 129 if err == io.EOF { 130 break 131 } else if err != nil { 132 return nil, err 133 } 134 135 pcrLog.PcrList = append(pcrLog.PcrList, pcrEvent) 136 } 137 } 138 139 return &pcrLog, nil 140 } 141 142 func readTPM2Log(firmware FirmwareType) (*PCRLog, error) { 143 var pcrLog PCRLog 144 var pcrEvent *TcgPcrEvent 145 146 file, err := os.Open(DefaultTCPABinaryLog) 147 if err != nil { 148 return nil, err 149 } 150 defer file.Close() 151 152 pcrLog.Firmware = firmware 153 154 if pcrEvent, err = parseTcgPcrEvent(file); err != nil { 155 return nil, err 156 } 157 if efiSpecId, err := parseEfiSpecEvent(bytes.NewBuffer(pcrEvent.event)); efiSpecId == nil { 158 if err != nil { 159 return nil, err 160 } 161 return nil, errors.New("First event was not an EFI SpecID Event") 162 } 163 164 pcrLog.PcrList = append(pcrLog.PcrList, pcrEvent) 165 166 for { 167 pcrEvent, err := parseTcgPcrEvent2(file) 168 if err == io.EOF { 169 break 170 } else if err != nil { 171 return nil, err 172 } 173 174 // There may be times when give part of the buffer past the last event, 175 // when that is the case just check to see if the event type is zero (reserved) 176 if pcrEvent.eventType == 0 { 177 break 178 } 179 pcrLog.PcrList = append(pcrLog.PcrList, pcrEvent) 180 } 181 182 return &pcrLog, nil 183 } 184 185 func getTaggedEvent(eventData []byte) (*string, error) { 186 var eventReader = bytes.NewReader(eventData) 187 var taggedEvent TCGPCClientTaggedEvent 188 189 if err := binary.Read(eventReader, binary.LittleEndian, &taggedEvent.taggedEventID); err != nil { 190 return nil, err 191 } 192 193 if err := binary.Read(eventReader, binary.LittleEndian, &taggedEvent.taggedEventDataSize); err != nil { 194 return nil, err 195 } 196 197 taggedEvent.taggedEventData = make([]byte, taggedEvent.taggedEventDataSize) 198 if err := binary.Read(eventReader, binary.LittleEndian, &taggedEvent.taggedEventData); err != nil { 199 return nil, err 200 } 201 202 eventInfo := fmt.Sprintf("Tag ID - %d - %s", taggedEvent.taggedEventID, string(taggedEvent.taggedEventData)) 203 return &eventInfo, nil 204 } 205 206 func getHandoffTablePointers(eventData []byte) (*string, error) { 207 var eventReader = bytes.NewReader(eventData) 208 var handoffTablePointers EFIHandoffTablePointers 209 210 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.numberOfTables); err != nil { 211 return nil, err 212 } 213 214 handoffTablePointers.tableEntry = make([]EFIConfigurationTable, handoffTablePointers.numberOfTables) 215 for i := uint64(0); i < handoffTablePointers.numberOfTables; i++ { 216 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.tableEntry[i].vendorGUID.blockA); err != nil { 217 return nil, err 218 } 219 220 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.tableEntry[i].vendorGUID.blockB); err != nil { 221 return nil, err 222 } 223 224 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.tableEntry[i].vendorGUID.blockC); err != nil { 225 return nil, err 226 } 227 228 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.tableEntry[i].vendorGUID.blockD); err != nil { 229 return nil, err 230 } 231 232 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.tableEntry[i].vendorGUID.blockE); err != nil { 233 return nil, err 234 } 235 236 if err := binary.Read(eventReader, binary.LittleEndian, &handoffTablePointers.tableEntry[i].vendorTable); err != nil { 237 return nil, err 238 } 239 } 240 241 eventInfo := fmt.Sprint("Tables: ") 242 for _, table := range handoffTablePointers.tableEntry { 243 guid := fmt.Sprintf("%x-%x-%x-%x-%x", table.vendorGUID.blockA, table.vendorGUID.blockB, table.vendorGUID.blockC, table.vendorGUID.blockD, table.vendorGUID.blockE) 244 eventInfo += fmt.Sprintf("At address 0x%d with Guid %s", table.vendorTable, guid) 245 } 246 return &eventInfo, nil 247 } 248 249 func getPlatformFirmwareBlob(eventData []byte) (*string, error) { 250 var eventReader = bytes.NewReader(eventData) 251 var platformFirmwareBlob EFIPlatformFirmwareBlob 252 253 if err := binary.Read(eventReader, binary.LittleEndian, &platformFirmwareBlob.blobBase); err != nil { 254 return nil, err 255 } 256 257 if err := binary.Read(eventReader, binary.LittleEndian, &platformFirmwareBlob.blobLength); err != nil { 258 return nil, err 259 } 260 261 eventInfo := fmt.Sprintf("Blob address - 0x%d - with size - %db", platformFirmwareBlob.blobBase, platformFirmwareBlob.blobLength) 262 return &eventInfo, nil 263 } 264 265 func getGPTEventString(eventData []byte) (*string, error) { 266 var eventReader = bytes.NewReader(eventData) 267 var gptEvent EFIGptData 268 269 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.Signature); err != nil { 270 return nil, err 271 } 272 273 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.Revision); err != nil { 274 return nil, err 275 } 276 277 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.Size); err != nil { 278 return nil, err 279 } 280 281 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.CRC); err != nil { 282 return nil, err 283 } 284 285 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.HeaderStartLBA); err != nil { 286 return nil, err 287 } 288 289 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.HeaderCopyStartLBA); err != nil { 290 return nil, err 291 } 292 293 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.FirstUsableLBA); err != nil { 294 return nil, err 295 } 296 297 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.LastUsableLBA); err != nil { 298 return nil, err 299 } 300 301 if err := binary.Read(eventReader, binary.LittleEndian, &gptEvent.uefiPartitionHeader.DiskGUID); err != nil { 302 return nil, err 303 } 304 305 // Stop here we only want to know which device was used here. 306 307 eventInfo := fmt.Sprint("Disk Guid - ") 308 eventInfo += gptEvent.uefiPartitionHeader.DiskGUID.String() 309 return &eventInfo, nil 310 } 311 312 func getImageLoadEventString(eventData []byte) (*string, error) { 313 var eventReader = bytes.NewReader(eventData) 314 var imageLoadEvent EFIImageLoadEvent 315 316 if err := binary.Read(eventReader, binary.LittleEndian, &imageLoadEvent.imageLocationInMemory); err != nil { 317 return nil, err 318 } 319 320 if err := binary.Read(eventReader, binary.LittleEndian, &imageLoadEvent.imageLengthInMemory); err != nil { 321 return nil, err 322 } 323 324 if err := binary.Read(eventReader, binary.LittleEndian, &imageLoadEvent.imageLinkTimeAddress); err != nil { 325 return nil, err 326 } 327 328 if err := binary.Read(eventReader, binary.LittleEndian, &imageLoadEvent.lengthOfDevicePath); err != nil { 329 return nil, err 330 } 331 332 // Stop here we only want to know which device was used here. 333 334 eventInfo := fmt.Sprintf("Image loaded at address 0x%d ", imageLoadEvent.imageLocationInMemory) 335 eventInfo += fmt.Sprintf("with %db", imageLoadEvent.imageLengthInMemory) 336 337 return &eventInfo, nil 338 } 339 340 func getVariableDataString(eventData []byte) (*string, error) { 341 var eventReader = bytes.NewReader(eventData) 342 var variableData EFIVariableData 343 344 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableName.blockA); err != nil { 345 return nil, err 346 } 347 348 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableName.blockB); err != nil { 349 return nil, err 350 } 351 352 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableName.blockC); err != nil { 353 return nil, err 354 } 355 356 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableName.blockD); err != nil { 357 return nil, err 358 } 359 360 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableName.blockE); err != nil { 361 return nil, err 362 } 363 364 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.unicodeNameLength); err != nil { 365 return nil, err 366 } 367 368 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableDataLength); err != nil { 369 return nil, err 370 } 371 372 variableData.unicodeName = make([]uint16, variableData.unicodeNameLength) 373 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.unicodeName); err != nil { 374 return nil, err 375 } 376 377 variableData.variableData = make([]byte, variableData.variableDataLength) 378 if err := binary.Read(eventReader, binary.LittleEndian, &variableData.variableData); err != nil { 379 return nil, err 380 } 381 382 guid := fmt.Sprintf("Variable - %x-%x-%x-%x-%x - ", variableData.variableName.blockA, variableData.variableName.blockB, variableData.variableName.blockC, variableData.variableName.blockD, variableData.variableName.blockE) 383 eventInfo := guid 384 utf16String := utf16.Decode(variableData.unicodeName) 385 eventInfo += fmt.Sprintf("%s", string(utf16String)) 386 387 return &eventInfo, nil 388 }