//go:build linux // +build linux // Package amdsevsnp contains minimal functionality required to fetch // attestation reports inside an enlightened guest. package amdsevsnp import ( "bytes" "encoding/binary" "encoding/hex" "fmt" "os" "unsafe" "github.com/Microsoft/hcsshim/internal/guest/linux" ) const ( msgTypeInvalid = iota msgCPUIDRequest msgCPUIDResponse msgKeyRequest msgKeyResponse msgReportRequest msgReportResponse msgExportRequest msgExportResponse msgImportRequest msgImportResponse msgAbsorbRequest msgAbsorbResponse msgVMRKRequest msgVMRKResponse msgTypeMax ) type guestRequest struct { RequestMsgType byte ResponseMsgType byte MsgVersion byte RequestLength uint16 RequestUAddr unsafe.Pointer ResponseLength uint16 ResponseUAddr unsafe.Pointer Error uint32 } // AMD SEV ioctl definitions. const ( // SEV-SNP IOCTL type. guestType = 'S' // SEV-SNP IOCTL size, same as unsafe.Sizeof(SevSNPGuestRequest{}). guestSize = 40 ioctlBase = linux.IocWRBase | guestType< len(msgReportIn.ReportData) { return nil, fmt.Errorf("reportData too large: %s", reportData) } copy(msgReportIn.ReportData[:], reportData) } payload := &guestRequest{ RequestMsgType: msgReportRequest, ResponseMsgType: msgReportResponse, MsgVersion: 1, RequestLength: uint16(unsafe.Sizeof(msgReportIn)), RequestUAddr: unsafe.Pointer(&msgReportIn), ResponseLength: uint16(unsafe.Sizeof(msgReportOut)), ResponseUAddr: unsafe.Pointer(&msgReportOut), Error: 0, } if err := linux.Ioctl(f, reportCode|ioctlBase, unsafe.Pointer(payload)); err != nil { return nil, err } return msgReportOut.Report[:], nil } // Report represents parsed attestation report. type Report struct { Version uint32 GuestSVN uint32 Policy uint64 FamilyID string ImageID string VMPL uint32 SignatureAlgo uint32 PlatformVersion uint64 PlatformInfo uint64 AuthorKeyEn uint32 ReportData string Measurement string HostData []byte IDKeyDigest string AuthorKeyDigest string ReportID string ReportIDMA string ReportTCB uint64 ChipID string CommittedSVN string CommittedVersion string LaunchSVN string Signature string } // mirrorBytes mirrors the byte ordering so that hex-encoding little endian // ordered bytes come out in the readable order. func mirrorBytes(b []byte) []byte { for i := 0; i < len(b)/2; i++ { mirrorIndex := len(b) - i - 1 b[i], b[mirrorIndex] = b[mirrorIndex], b[i] } return b } // FetchParsedSNPReport parses raw attestation response into proper structs. func FetchParsedSNPReport(reportData []byte) (Report, error) { rawBytes, err := FetchRawSNPReport(reportData) if err != nil { return Report{}, err } var r report buf := bytes.NewBuffer(rawBytes) if err := binary.Read(buf, binary.LittleEndian, &r); err != nil { return Report{}, err } return r.report(), nil }