...

Source file src/github.com/Microsoft/hcsshim/pkg/amdsevsnp/report.go

Documentation: github.com/Microsoft/hcsshim/pkg/amdsevsnp

     1  //go:build linux
     2  // +build linux
     3  
     4  // Package amdsevsnp contains minimal functionality required to fetch
     5  // attestation reports inside an enlightened guest.
     6  package amdsevsnp
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/binary"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"os"
    14  	"unsafe"
    15  
    16  	"github.com/Microsoft/hcsshim/internal/guest/linux"
    17  )
    18  
    19  const (
    20  	msgTypeInvalid = iota
    21  	msgCPUIDRequest
    22  	msgCPUIDResponse
    23  	msgKeyRequest
    24  	msgKeyResponse
    25  	msgReportRequest
    26  	msgReportResponse
    27  	msgExportRequest
    28  	msgExportResponse
    29  	msgImportRequest
    30  	msgImportResponse
    31  	msgAbsorbRequest
    32  	msgAbsorbResponse
    33  	msgVMRKRequest
    34  	msgVMRKResponse
    35  	msgTypeMax
    36  )
    37  
    38  type guestRequest struct {
    39  	RequestMsgType  byte
    40  	ResponseMsgType byte
    41  	MsgVersion      byte
    42  	RequestLength   uint16
    43  	RequestUAddr    unsafe.Pointer
    44  	ResponseLength  uint16
    45  	ResponseUAddr   unsafe.Pointer
    46  	Error           uint32
    47  }
    48  
    49  // AMD SEV ioctl definitions.
    50  const (
    51  	// SEV-SNP IOCTL type.
    52  	guestType = 'S'
    53  	// SEV-SNP IOCTL size, same as unsafe.Sizeof(SevSNPGuestRequest{}).
    54  	guestSize = 40
    55  	ioctlBase = linux.IocWRBase | guestType<<linux.IocTypeShift | guestSize<<linux.IocSizeShift
    56  
    57  	// SEV-SNP requests
    58  	reportCode = 0x1
    59  )
    60  
    61  // reportRequest used to issue SEV-SNP request
    62  // https://www.amd.com/system/files/TechDocs/56860.pdf
    63  // MSG_REPORT_REQ Table 20.
    64  type reportRequest struct {
    65  	ReportData [64]byte
    66  	VMPL       uint32
    67  	_          [28]byte
    68  }
    69  
    70  // report is an internal representation of SEV-SNP report
    71  // https://www.amd.com/system/files/TechDocs/56860.pdf
    72  // ATTESTATION_REPORT Table 21.
    73  type report struct {
    74  	Version          uint32
    75  	GuestSVN         uint32
    76  	Policy           uint64
    77  	FamilyID         [16]byte
    78  	ImageID          [16]byte
    79  	VMPL             uint32
    80  	SignatureAlgo    uint32
    81  	PlatformVersion  uint64
    82  	PlatformInfo     uint64
    83  	AuthorKeyEn      uint32
    84  	Reserved1        uint32
    85  	ReportData       [64]byte
    86  	Measurement      [48]byte
    87  	HostData         [32]byte
    88  	IDKeyDigest      [48]byte
    89  	AuthorKeyDigest  [48]byte
    90  	ReportID         [32]byte
    91  	ReportIDMA       [32]byte
    92  	ReportTCB        uint64
    93  	Reserved2        [24]byte
    94  	ChipID           [64]byte
    95  	CommittedSVN     [8]byte
    96  	CommittedVersion [8]byte
    97  	LaunchSVN        [8]byte
    98  	Reserved3        [168]byte
    99  	Signature        [512]byte
   100  }
   101  
   102  func (sr *report) report() Report {
   103  	return Report{
   104  		Version:          sr.Version,
   105  		GuestSVN:         sr.GuestSVN,
   106  		Policy:           sr.Policy,
   107  		FamilyID:         hex.EncodeToString(mirrorBytes(sr.FamilyID[:])[:]),
   108  		ImageID:          hex.EncodeToString(mirrorBytes(sr.ImageID[:])[:]),
   109  		VMPL:             sr.VMPL,
   110  		SignatureAlgo:    sr.SignatureAlgo,
   111  		PlatformVersion:  sr.PlatformVersion,
   112  		PlatformInfo:     sr.PlatformInfo,
   113  		AuthorKeyEn:      sr.AuthorKeyEn,
   114  		ReportData:       hex.EncodeToString(sr.ReportData[:]),
   115  		Measurement:      hex.EncodeToString(sr.Measurement[:]),
   116  		HostData:         sr.HostData[:],
   117  		IDKeyDigest:      hex.EncodeToString(sr.IDKeyDigest[:]),
   118  		AuthorKeyDigest:  hex.EncodeToString(sr.AuthorKeyDigest[:]),
   119  		ReportID:         hex.EncodeToString(sr.ReportID[:]),
   120  		ReportIDMA:       hex.EncodeToString(sr.ReportIDMA[:]),
   121  		ReportTCB:        sr.ReportTCB,
   122  		ChipID:           hex.EncodeToString(sr.ChipID[:]),
   123  		CommittedSVN:     hex.EncodeToString(sr.CommittedSVN[:]),
   124  		CommittedVersion: hex.EncodeToString(sr.CommittedVersion[:]),
   125  		LaunchSVN:        hex.EncodeToString(sr.LaunchSVN[:]),
   126  		Signature:        hex.EncodeToString(sr.Signature[:]),
   127  	}
   128  }
   129  
   130  // reportResponse is the attestation response struct
   131  // https://www.amd.com/system/files/TechDocs/56860.pdf
   132  // MSG_REPORT_RSP Table 23.
   133  // NOTE: reportResponse.Report is a byte slice, to have the original
   134  // response in bytes. The conversion to internal struct happens inside
   135  // convertRawReport.
   136  //
   137  // NOTE: the additional 64 bytes are reserved, without them, the ioctl fails.
   138  type reportResponse struct {
   139  	Status     uint32
   140  	ReportSize uint32
   141  	reserved1  [24]byte
   142  	Report     [1184]byte
   143  	reserved2  [64]byte // padding to the size of SEV_SNP_REPORT_RSP_BUF_SZ (i.e., 1280 bytes)
   144  }
   145  
   146  // FetchRawSNPReport returns attestation report bytes.
   147  func FetchRawSNPReport(reportData []byte) ([]byte, error) {
   148  	f, err := os.OpenFile("/dev/sev", os.O_RDWR, 0)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	defer func() {
   153  		_ = f.Close()
   154  	}()
   155  
   156  	var (
   157  		msgReportIn  reportRequest
   158  		msgReportOut reportResponse
   159  	)
   160  
   161  	if reportData != nil {
   162  		if len(reportData) > len(msgReportIn.ReportData) {
   163  			return nil, fmt.Errorf("reportData too large: %s", reportData)
   164  		}
   165  		copy(msgReportIn.ReportData[:], reportData)
   166  	}
   167  
   168  	payload := &guestRequest{
   169  		RequestMsgType:  msgReportRequest,
   170  		ResponseMsgType: msgReportResponse,
   171  		MsgVersion:      1,
   172  		RequestLength:   uint16(unsafe.Sizeof(msgReportIn)),
   173  		RequestUAddr:    unsafe.Pointer(&msgReportIn),
   174  		ResponseLength:  uint16(unsafe.Sizeof(msgReportOut)),
   175  		ResponseUAddr:   unsafe.Pointer(&msgReportOut),
   176  		Error:           0,
   177  	}
   178  
   179  	if err := linux.Ioctl(f, reportCode|ioctlBase, unsafe.Pointer(payload)); err != nil {
   180  		return nil, err
   181  	}
   182  	return msgReportOut.Report[:], nil
   183  }
   184  
   185  // Report represents parsed attestation report.
   186  type Report struct {
   187  	Version          uint32
   188  	GuestSVN         uint32
   189  	Policy           uint64
   190  	FamilyID         string
   191  	ImageID          string
   192  	VMPL             uint32
   193  	SignatureAlgo    uint32
   194  	PlatformVersion  uint64
   195  	PlatformInfo     uint64
   196  	AuthorKeyEn      uint32
   197  	ReportData       string
   198  	Measurement      string
   199  	HostData         []byte
   200  	IDKeyDigest      string
   201  	AuthorKeyDigest  string
   202  	ReportID         string
   203  	ReportIDMA       string
   204  	ReportTCB        uint64
   205  	ChipID           string
   206  	CommittedSVN     string
   207  	CommittedVersion string
   208  	LaunchSVN        string
   209  	Signature        string
   210  }
   211  
   212  // mirrorBytes mirrors the byte ordering so that hex-encoding little endian
   213  // ordered bytes come out in the readable order.
   214  func mirrorBytes(b []byte) []byte {
   215  	for i := 0; i < len(b)/2; i++ {
   216  		mirrorIndex := len(b) - i - 1
   217  		b[i], b[mirrorIndex] = b[mirrorIndex], b[i]
   218  	}
   219  	return b
   220  }
   221  
   222  // FetchParsedSNPReport parses raw attestation response into proper structs.
   223  func FetchParsedSNPReport(reportData []byte) (Report, error) {
   224  	rawBytes, err := FetchRawSNPReport(reportData)
   225  	if err != nil {
   226  		return Report{}, err
   227  	}
   228  
   229  	var r report
   230  	buf := bytes.NewBuffer(rawBytes)
   231  	if err := binary.Read(buf, binary.LittleEndian, &r); err != nil {
   232  		return Report{}, err
   233  	}
   234  	return r.report(), nil
   235  }
   236  

View as plain text