Skip to content

Commit

Permalink
Add product utility unit tests
Browse files Browse the repository at this point in the history
Improves test coverage, but also expands GetAttestationFromReport to
fill in the Product field of the Attestation message from the fetched
VCEK/VLEK certificate's extension.

Signed-off-by: Dionna Glaze <[email protected]>
  • Loading branch information
deeglaze committed Oct 21, 2023
1 parent 1a9dbbc commit 9fd65c9
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 8 deletions.
50 changes: 50 additions & 0 deletions abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"
spb "github.com/google/go-sev-guest/proto/sevsnp"
"github.com/pborman/uuid"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/wrapperspb"
)

var emptyReport = `
Expand Down Expand Up @@ -267,3 +270,50 @@ func TestCertTableProto(t *testing.T) {
t.Fatalf("Extras[%q] = %v, want %v", extraGUID, gotExtra, extraraw)
}
}

func TestSevProduct(t *testing.T) {
oldCpuid := cpuid
defer func() { cpuid = oldCpuid }()
tcs := []struct {
eax uint32
want *spb.SevProduct
}{
{
eax: 0x00a00f10,
want: &spb.SevProduct{
Name: spb.SevProduct_SEV_PRODUCT_MILAN,
MachineStepping: &wrapperspb.UInt32Value{Value: 0}},
},
{
eax: 0x00a00f11,
want: &spb.SevProduct{
Name: spb.SevProduct_SEV_PRODUCT_MILAN,
MachineStepping: &wrapperspb.UInt32Value{Value: 1}},
},
{
eax: 0x00a10f10,
want: &spb.SevProduct{
Name: spb.SevProduct_SEV_PRODUCT_GENOA,
MachineStepping: &wrapperspb.UInt32Value{Value: 0}},
},
{
eax: 0x00a10f12,
want: &spb.SevProduct{
Name: spb.SevProduct_SEV_PRODUCT_GENOA,
MachineStepping: &wrapperspb.UInt32Value{Value: 2}},
},
{
eax: 0x0b010f0,
want: &spb.SevProduct{
Name: spb.SevProduct_SEV_PRODUCT_UNKNOWN,
MachineStepping: &wrapperspb.UInt32Value{Value: 0}},
},
}
for _, tc := range tcs {
cpuid = func(op uint32) (uint32, uint32, uint32, uint32) { return tc.eax, 0, 0, 0 }
got := SevProduct()
if diff := cmp.Diff(got, tc.want, protocmp.Transform()); diff != "" {
t.Errorf("SevProduct() = %+v, want %+v. Diff: %s", got, tc.want, diff)
}
}
}
6 changes: 6 additions & 0 deletions kds/kds.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ func preEndorsementKeyCertificateExtensions(cert *x509.Certificate) (*Extensions
// VcekCertificateExtensions returns the x509v3 extensions from the KDS specification of a VCEK
// certificate interpreted into a struct type.
func VcekCertificateExtensions(cert *x509.Certificate) (*Extensions, error) {
if cert == nil {
return nil, fmt.Errorf("cert cannot be nil")
}
exts, err := preEndorsementKeyCertificateExtensions(cert)
if err != nil {
return nil, err
Expand All @@ -422,6 +425,9 @@ func VcekCertificateExtensions(cert *x509.Certificate) (*Extensions, error) {
// VlekCertificateExtensions returns the x509v3 extensions from the KDS specification of a VLEK
// certificate interpreted into a struct type.
func VlekCertificateExtensions(cert *x509.Certificate) (*Extensions, error) {
if cert == nil {
return nil, fmt.Errorf("cert cannot be nil")
}
exts, err := preEndorsementKeyCertificateExtensions(cert)
if err != nil {
return nil, err
Expand Down
30 changes: 30 additions & 0 deletions kds/kds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,30 @@ func TestProductName(t *testing.T) {
},
want: "badstepping",
},
{
name: "unknown milan stepping",
input: &pb.SevProduct{
Name: pb.SevProduct_SEV_PRODUCT_MILAN,
MachineStepping: &wrapperspb.UInt32Value{Value: 15},
},
want: "unmappedMilanStepping",
},
{
name: "unknown genoa stepping",
input: &pb.SevProduct{
Name: pb.SevProduct_SEV_PRODUCT_GENOA,
MachineStepping: &wrapperspb.UInt32Value{Value: 15},
},
want: "unmappedGenoaStepping",
},
{
name: "unknown",
input: &pb.SevProduct{
Name: pb.SevProduct_SEV_PRODUCT_UNKNOWN,
MachineStepping: &wrapperspb.UInt32Value{Value: 15},
},
want: "Unknown",
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
Expand Down Expand Up @@ -266,6 +290,12 @@ func TestParseProductName(t *testing.T) {
Name: pb.SevProduct_SEV_PRODUCT_GENOA,
},
},
{
name: "Unhandled report signer",
input: "ignored",
key: abi.NoneReportSigner,
wantErr: "internal: unhandled reportSigner",
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
Expand Down
19 changes: 18 additions & 1 deletion verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ func checkProductName(got, want *spb.SevProduct, key abi.ReportSigner) error {
return fmt.Errorf("stepping value in VCEK certificate should not be nil")
}
if got.MachineStepping.Value != want.MachineStepping.Value {
return fmt.Errorf("%v cert product stepping number %02X is not %02X",
return fmt.Errorf("%v cert product stepping number 0x%X is not 0x%X",
key, got.MachineStepping.Value, want.MachineStepping.Value)
}
}
Expand Down Expand Up @@ -772,6 +772,23 @@ func GetAttestationFromReport(report *spb.Report, options *Options) (*spb.Attest
if err := fillInAttestation(result, options); err != nil {
return nil, err
}
// Attempt to fill in the product field of the attestation. Don't error at this
// point since this is not validation.
info, _ := abi.ParseSignerInfo(report.SignerInfo)
var exts *kds.Extensions
parse := func(der []byte) *x509.Certificate {
out, _ := x509.ParseCertificate(der)
return out
}
switch info.SigningKey {
case abi.VcekReportSigner:
exts, _ = kds.VcekCertificateExtensions(parse(result.CertificateChain.VcekCert))
case abi.VlekReportSigner:
exts, _ = kds.VlekCertificateExtensions(parse(result.CertificateChain.VlekCert))
}
if exts != nil {
result.Product, _ = kds.ParseProductName(exts.ProductName, info.SigningKey)
}
return result, nil
}

Expand Down
33 changes: 26 additions & 7 deletions verify/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,13 +557,32 @@ func TestRealAttestationVerification(t *testing.T) {
"https://kdsintf.amd.com/vcek/v1/Milan/3ac3fe21e13fb0990eb28a802e3fb6a29483a6b0753590c951bdd3b8e53786184ca39e359669a2b76a1936776b564ea464cdce40c05f63c9b610c5068b006b5d?blSPL=2&teeSPL=0&snpSPL=5&ucodeSPL=68": testdata.VcekBytes,
},
)
if err := RawSnpReport(testdata.AttestationBytes, &Options{
Getter: getter,
Product: &pb.SevProduct{
Name: pb.SevProduct_SEV_PRODUCT_MILAN,
MachineStepping: &wrapperspb.UInt32Value{Value: 0},
}}); err != nil {
t.Error(err)
tcs := []struct {
name string
product *pb.SevProduct
wantErr string
}{
{
name: "happy path",
product: &pb.SevProduct{
Name: pb.SevProduct_SEV_PRODUCT_MILAN,
MachineStepping: &wrapperspb.UInt32Value{Value: 0},
},
},
{
name: "bad vcek stepping",
product: &pb.SevProduct{
Name: pb.SevProduct_SEV_PRODUCT_MILAN,
MachineStepping: &wrapperspb.UInt32Value{Value: 12},
},
wantErr: "cert product stepping number 0x0 is not 0xC",
},
}
for _, tc := range tcs {
opts := &Options{Getter: getter, Product: tc.product}
if err := RawSnpReport(testdata.AttestationBytes, opts); !test.Match(err, tc.wantErr) {
t.Errorf("RawSnpReport(_, %+v) = %v errored unexpectedly. Want %q", opts, err, tc.wantErr)
}
}
}

Expand Down

0 comments on commit 9fd65c9

Please sign in to comment.