github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/pkg/securelaunch/measurement/files.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 measurement
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"log"
    14  
    15  	"github.com/u-root/u-root/pkg/mount"
    16  	slaunch "github.com/u-root/u-root/pkg/securelaunch"
    17  	"github.com/u-root/u-root/pkg/securelaunch/tpm"
    18  )
    19  
    20  /* describes the "files" portion of policy file */
    21  type FileCollector struct {
    22  	Type  string   `json:"type"`
    23  	Paths []string `json:"paths"`
    24  }
    25  
    26  /*
    27   * NewFileCollector extracts the "files" portion from the policy file.
    28   * initializes a new FileCollector structure.
    29   * returns error if unmarshalling of FileCollector fails
    30   */
    31  func NewFileCollector(config []byte) (Collector, error) {
    32  	slaunch.Debug("New Files Collector initialized\n")
    33  	var fc = new(FileCollector)
    34  	err := json.Unmarshal(config, &fc)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return fc, nil
    39  }
    40  
    41  /*
    42   * HashFile reads file input by user and calls TPM to measure it and store the hash.
    43   *
    44   * inputVal is of format <block device identifier>:<path>
    45   * E.g sda:/path/to/file _OR UUID:/path/to/file
    46   * Performs following actions
    47   * 1. mount device
    48   * 2. Read file on device into a byte slice.
    49   * 3. Unmount device
    50   * 4. Call tpm package which measures byte slice and stores it.
    51   */
    52  func HashFile(tpmHandle io.ReadWriteCloser, inputVal string) error {
    53  	// inputVal is of type sda:path
    54  	mntFilePath, mountPath, e := slaunch.GetMountedFilePath(inputVal, mount.MS_RDONLY)
    55  	if e != nil {
    56  		log.Printf("HashFile: GetMountedFilePath err=%v", e)
    57  		return fmt.Errorf("failed to get mount path, err=%v", e)
    58  	}
    59  	slaunch.Debug("File Collector: Reading file=%s", mntFilePath)
    60  
    61  	slaunch.Debug("File Collector: fileP=%s, mountP=%s\n", mntFilePath, mountPath)
    62  	d, err := ioutil.ReadFile(mntFilePath)
    63  	if e := mount.Unmount(mountPath, true, false); e != nil {
    64  		log.Printf("File Collector: Unmount failed. PANIC\n")
    65  		panic(e)
    66  	}
    67  
    68  	if err != nil {
    69  		return fmt.Errorf("failed to read target file: filePath=%s, mountPath=%s, inputVal=%s, err=%v",
    70  			mntFilePath, mountPath, inputVal, err)
    71  	}
    72  
    73  	return tpm.ExtendPCRDebug(tpmHandle, pcr, bytes.NewReader(d))
    74  }
    75  
    76  /*
    77   * Collect satisfies Collector Interface. It loops over all file paths provided by user
    78   * and for each file path,  calls HashFile. HashFile measures each file on
    79   * that path and stores the result in TPM.
    80   */
    81  func (s *FileCollector) Collect(tpmHandle io.ReadWriteCloser) error {
    82  
    83  	for _, inputVal := range s.Paths {
    84  		// inputVal is of type sda:/path/to/file
    85  		err := HashFile(tpmHandle, inputVal)
    86  		if err != nil {
    87  			log.Printf("File Collector: input=%s, err = %v", inputVal, err)
    88  			return err
    89  		}
    90  	}
    91  
    92  	return nil
    93  }