-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #105 from deeglaze/show
Add a 'show' tool and more abi functions
- Loading branch information
Showing
5 changed files
with
239 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// Package report provides functions for reading and writing attestation reports of various formats. | ||
package report | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/google/go-sev-guest/abi" | ||
"github.com/google/go-sev-guest/kds" | ||
"go.uber.org/multierr" | ||
"google.golang.org/protobuf/encoding/prototext" | ||
"google.golang.org/protobuf/proto" | ||
|
||
spb "github.com/google/go-sev-guest/proto/sevsnp" | ||
) | ||
|
||
func parseAttestationBytes(b []byte) (*spb.Attestation, error) { | ||
// This format is the attestation report in AMD's specified ABI format, immediately | ||
// followed by the certificate table bytes. | ||
if len(b) < abi.ReportSize { | ||
return nil, fmt.Errorf("attestation contents too small (0x%x bytes). Want at least 0x%x bytes", len(b), abi.ReportSize) | ||
} | ||
reportBytes := b[0:abi.ReportSize] | ||
certBytes := b[abi.ReportSize:] | ||
|
||
report, err := abi.ReportToProto(reportBytes) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not parse attestation report: %v", err) | ||
} | ||
|
||
certs := new(abi.CertTable) | ||
if err := certs.Unmarshal(certBytes); err != nil { | ||
return nil, fmt.Errorf("could not parse certificate table: %v", err) | ||
} | ||
return &spb.Attestation{Report: report, CertificateChain: certs.Proto()}, nil | ||
} | ||
|
||
// ParseAttestation parses an attestation report from a byte slice as a given format. | ||
func ParseAttestation(b []byte, inform string) (*spb.Attestation, error) { | ||
switch inform { | ||
case "bin": | ||
// May have empty certificate buffer to be just a report. | ||
return parseAttestationBytes(b) | ||
case "proto": | ||
result := &spb.Attestation{} | ||
aerr := proto.Unmarshal(b, result) | ||
var rerr error | ||
if aerr != nil { | ||
result.Report = &spb.Report{} | ||
rerr = proto.Unmarshal(b, result.Report) | ||
if rerr != nil { | ||
return nil, fmt.Errorf("could not parse as proto: %v", multierr.Append(aerr, rerr)) | ||
} | ||
} | ||
return result, nil | ||
case "textproto": | ||
result := &spb.Attestation{} | ||
aerr := prototext.Unmarshal(b, result) | ||
var rerr error | ||
if aerr != nil { | ||
result.Report = &spb.Report{} | ||
rerr = prototext.Unmarshal(b, result.Report) | ||
if rerr != nil { | ||
return nil, fmt.Errorf("could not parse as textproto: %v", multierr.Append(aerr, rerr)) | ||
} | ||
} | ||
default: | ||
return nil, fmt.Errorf("unknown inform: %q", inform) | ||
} | ||
// This should be impossible. | ||
return nil, errors.New("internal error") | ||
} | ||
|
||
// GetAttestation reads an attestation report from a file. | ||
func GetAttestation(infile, inform string) (*spb.Attestation, error) { | ||
var in io.Reader | ||
var f *os.File | ||
if infile == "-" { | ||
in = os.Stdin | ||
} else { | ||
file, err := os.Open(infile) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not open %q: %v", infile, err) | ||
} | ||
f = file | ||
in = file | ||
} | ||
defer func() { | ||
if f != nil { | ||
f.Close() | ||
} | ||
}() | ||
|
||
contents, err := io.ReadAll(in) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not read %q: %v", infile, err) | ||
} | ||
return ParseAttestation(contents, inform) | ||
} | ||
|
||
func asBin(report *spb.Attestation) ([]byte, error) { | ||
r, err := abi.ReportToAbiBytes(report.Report) | ||
if err != nil { | ||
return nil, err | ||
} | ||
certs := abi.CertsFromProto(report.CertificateChain).Marshal() | ||
return append(r, certs...), nil | ||
} | ||
|
||
func tcbBreakdown(tcb uint64) string { | ||
parts := kds.DecomposeTCBVersion(kds.TCBVersion(tcb)) | ||
return fmt.Sprintf("0x%x:{ucode: %d, snp: %d, tee: %d, bl: %d}", tcb, parts.UcodeSpl, parts.SnpSpl, | ||
parts.TeeSpl, parts.BlSpl) | ||
} | ||
|
||
func tcbText(report *spb.Attestation) ([]byte, error) { | ||
return []byte(fmt.Sprintf("current_tcb=%s\ncommitted_tcb=%s\nlaunch_tcb=%s\n", | ||
tcbBreakdown(report.Report.GetCurrentTcb()), | ||
tcbBreakdown(report.Report.GetCommittedTcb()), | ||
tcbBreakdown(report.Report.GetLaunchTcb()))), nil | ||
} | ||
|
||
// Transform returns the attestation in the outform marshalled format. | ||
func Transform(report *spb.Attestation, outform string) ([]byte, error) { | ||
switch outform { | ||
case "bin": | ||
return asBin(report) | ||
case "proto": | ||
return proto.Marshal(report) | ||
case "textproto": | ||
return prototext.MarshalOptions{Multiline: true, Indent: " "}.Marshal(report) | ||
case "tcb": | ||
return tcbText(report) | ||
default: | ||
return nil, fmt.Errorf("unknown outform: %q", outform) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// show reads an attestation report and outputs it in a preferred format. | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"os" | ||
|
||
"github.com/google/go-sev-guest/tools/lib/report" | ||
"github.com/google/logger" | ||
) | ||
|
||
var ( | ||
infile = flag.String("in", "-", "Path to attestation file, or - for stdin.") | ||
inform = flag.String("inform", "in", "Format of the attestation file. "+ | ||
"One of bin, proto, textproto") | ||
outfile = flag.String("out", "-", "Path to output file, or - for stdout.") | ||
outform = flag.String("outform", "textproto", "Format of the output file. "+ | ||
"One of bin, proto, textproto, tcb. Tcb is human-readable.") | ||
) | ||
|
||
func main() { | ||
logger.Init("", false, false, os.Stderr) | ||
flag.Parse() | ||
|
||
attestation, err := report.GetAttestation(*infile, *inform) | ||
if err != nil { | ||
logger.Fatal(err) | ||
} | ||
|
||
bin, err := report.Transform(attestation, *outform) | ||
if err != nil { | ||
logger.Fatal(err) | ||
} | ||
|
||
out := os.Stdout | ||
if *outfile != "-" { | ||
out, err = os.OpenFile(*outfile, os.O_WRONLY|os.O_CREATE, 0644) | ||
if err != nil { | ||
logger.Fatalf("Could not open %q: %v", *outfile, err) | ||
} | ||
} | ||
|
||
if _, err := out.Write(bin); err != nil { | ||
logger.Fatalf("Could not write attestation to %q: %v", *outfile, err) | ||
} | ||
} |