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  }