Skip to content

Commit

Permalink
attestation: implement Stringer in validator as unique identifier
Browse files Browse the repository at this point in the history
  • Loading branch information
jmxnzo committed Jan 2, 2025
1 parent 6811d6d commit 4e7c967
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 23 deletions.
13 changes: 8 additions & 5 deletions coordinator/internal/authority/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"log/slog"
"net"
"strings"
"time"

"github.com/edgelesssys/contrast/internal/atls"
Expand Down Expand Up @@ -86,10 +87,11 @@ func (c *Credentials) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.A
return nil, nil, fmt.Errorf("generating SNP validation options: %w", err)
}

for _, opt := range opts {
for i, opt := range opts {
name := fmt.Sprintf("snp-%d-%s", i, strings.TrimPrefix(opt.VerifyOpts.Product.Name.String(), "SEV_PRODUCT_"))
validator := snp.NewValidatorWithReportSetter(opt.VerifyOpts, opt.ValidateOpts,
logger.NewWithAttrs(logger.NewNamed(c.logger, "validator"), map[string]string{"tee-type": "snp"}),
&authInfo)
logger.NewWithAttrs(logger.NewNamed(c.logger, "validator"), map[string]string{"reference-values": name}),
&authInfo, name)
validators = append(validators, validator)
}

Expand All @@ -98,9 +100,10 @@ func (c *Credentials) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.A
log.Error("Could not generate TDX validation options", "error", err)
return nil, nil, fmt.Errorf("generating TDX validation options: %w", err)
}
for _, opt := range tdxOpts {
for i, opt := range tdxOpts {
name := fmt.Sprintf("tdx-%d", i)
validators = append(validators, tdx.NewValidatorWithReportSetter(&tdx.StaticValidateOptsGenerator{Opts: opt},
logger.NewWithAttrs(logger.NewNamed(c.logger, "validator"), map[string]string{"tee-type": "tdx"}), &authInfo))
logger.NewWithAttrs(logger.NewNamed(c.logger, "validator"), map[string]string{"reference-values": name}), &authInfo, name))
}

serverCfg, err := atls.CreateAttestationServerTLSConfig(c.issuer, validators, c.attestationFailuresCounter)
Expand Down
14 changes: 13 additions & 1 deletion internal/atls/atls.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -94,6 +95,7 @@ type Issuer interface {
type Validator interface {
Getter
Validate(attDoc []byte, nonce []byte, peerPublicKey []byte) error
fmt.Stringer
}

// getATLSConfigForClientFunc returns a config setup function that is called once for every client connecting to the server.
Expand Down Expand Up @@ -248,7 +250,7 @@ func verifyEmbeddedReport(validators []Validator, cert *x509.Certificate, peerPu
return nil
}
// Otherwise, we'll keep track of the error and continue with the next validator.
retErr = errors.Join(retErr, fmt.Errorf("validator %s failed: %w", validator.OID(), validationErr))
retErr = errors.Join(retErr, fmt.Errorf(" validator %s failed: %w", validator.String(), validationErr))
}
}

Expand All @@ -260,6 +262,11 @@ func verifyEmbeddedReport(validators []Validator, cert *x509.Certificate, peerPu
return ErrNoMatchingValidators
}

// The joined error should reveal the atls nonce once to maintain readability.
if retErr != nil {
retErr = fmt.Errorf("with AtlsConnectionNonce %s: %w", hex.EncodeToString(nonce), retErr)
}

// If we're here, an error must've happened during validation.
return retErr
}
Expand Down Expand Up @@ -439,6 +446,11 @@ func (v FakeValidator) Validate(attDoc []byte, nonce []byte, _ []byte) error {
return v.err
}

// String returns the name as identifier of the validator.
func (v *FakeValidator) String() string {
return ""
}

// FakeAttestationDoc is a fake attestation document used for testing.
type FakeAttestationDoc struct {
UserData []byte
Expand Down
20 changes: 14 additions & 6 deletions internal/attestation/snp/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,45 @@ type Validator struct {
validateOpts *validate.Options
reportSetter attestation.ReportSetter
logger *slog.Logger
name string
}

// NewValidator returns a new Validator.
func NewValidator(VerifyOpts *verify.Options, ValidateOpts *validate.Options, log *slog.Logger) *Validator {
func NewValidator(VerifyOpts *verify.Options, ValidateOpts *validate.Options, log *slog.Logger, name string) *Validator {
return &Validator{
verifyOpts: VerifyOpts,
validateOpts: ValidateOpts,
logger: log,
name: name,
}
}

// NewValidatorWithReportSetter returns a new Validator with a report setter.
func NewValidatorWithReportSetter(VerifyOpts *verify.Options, ValidateOpts *validate.Options,
log *slog.Logger, reportSetter attestation.ReportSetter,
log *slog.Logger, reportSetter attestation.ReportSetter, name string,
) *Validator {
return &Validator{
verifyOpts: VerifyOpts,
validateOpts: ValidateOpts,
reportSetter: reportSetter,
logger: log,
name: name,
}
}

// OID returns the OID of the validator.
// OID returns the OID for the raw SNP report extension used by the validator.
func (v *Validator) OID() asn1.ObjectIdentifier {
return oid.RawSNPReport
}

// Validate a TPM based attestation.
func (v *Validator) Validate(attDocRaw []byte, nonce []byte, peerPublicKey []byte) (err error) {
v.logger.Info("Validate called", "nonce", hex.EncodeToString(nonce))
v.logger.Info("Validate called", "name", v.name, "nonce", hex.EncodeToString(nonce))
defer func() {
if err != nil {
v.logger.Error("Validation failed", "error", err)
v.logger.Debug("Validate failed", "name", v.name, "nonce", hex.EncodeToString(nonce), "error", err)
} else {
v.logger.Info("Validation successful")
v.logger.Info("Validate succeeded", "name", v.name, "nonce", hex.EncodeToString(nonce))
}
}()

Expand Down Expand Up @@ -99,6 +102,11 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte, peerPublicKey []byt
return nil
}

// String returns the name as identifier of the validator.
func (v *Validator) String() string {
return v.name
}

type snpReport struct {
report *sevsnp.Report
}
Expand Down
21 changes: 14 additions & 7 deletions internal/attestation/tdx/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Validator struct {
validateOptsGen validateOptsGenerator
reportSetter attestation.ReportSetter
logger *slog.Logger
name string
}

type validateOptsGenerator interface {
Expand All @@ -55,21 +56,22 @@ func (v *StaticValidateOptsGenerator) TDXValidateOpts(_ *tdx.QuoteV4) (*validate
}

// NewValidator returns a new Validator.
func NewValidator(optsGen validateOptsGenerator, log *slog.Logger) *Validator {
func NewValidator(optsGen validateOptsGenerator, log *slog.Logger, name string) *Validator {
return &Validator{
validateOptsGen: optsGen,
logger: log,
name: name,
}
}

// NewValidatorWithReportSetter returns a new Validator with a report setter.
func NewValidatorWithReportSetter(optsGen validateOptsGenerator, log *slog.Logger, reportSetter attestation.ReportSetter) *Validator {
v := NewValidator(optsGen, log)
func NewValidatorWithReportSetter(optsGen validateOptsGenerator, log *slog.Logger, reportSetter attestation.ReportSetter, name string) *Validator {
v := NewValidator(optsGen, log, name)
v.reportSetter = reportSetter
return v
}

// OID returns the OID of the validator.
// OID returns the OID for the raw TDX report extension used by the validator.
func (v *Validator) OID() asn1.ObjectIdentifier {
return oid.RawTDXReport
}
Expand All @@ -78,12 +80,12 @@ func (v *Validator) OID() asn1.ObjectIdentifier {
func (v *Validator) Validate(attDocRaw []byte, nonce []byte, peerPublicKey []byte) (err error) {
// TODO(freax13): Validate the memory integrity mode (logical vs cryptographic) in the provisioning certificate.

v.logger.Info("Validate called", "nonce", hex.EncodeToString(nonce))
v.logger.Info("Validate called", "name", v.name, "nonce", hex.EncodeToString(nonce))
defer func() {
if err != nil {
v.logger.Error("Validation failed", "error", err)
v.logger.Debug("Validate failed", "name", v.name, "nonce", hex.EncodeToString(nonce), "error", err)
} else {
v.logger.Info("Validation successful")
v.logger.Info("Validate succeeded", "name", v.name, "nonce", hex.EncodeToString(nonce))
}
}()

Expand Down Expand Up @@ -137,6 +139,11 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte, peerPublicKey []byt
return nil
}

// String returns the name as identifier of the validator.
func (v *Validator) String() string {
return v.name
}

func trustedRoots() (*x509.CertPool, error) {
rootCerts := x509.NewCertPool()
if ok := rootCerts.AppendCertsFromPEM(tdxRootCert); !ok {
Expand Down
11 changes: 7 additions & 4 deletions sdk/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package sdk
import (
"fmt"
"log/slog"
"strings"

"github.com/edgelesssys/contrast/internal/atls"
"github.com/edgelesssys/contrast/internal/attestation/certcache"
Expand All @@ -31,10 +32,11 @@ func ValidatorsFromManifest(kdsDir string, m *manifest.Manifest, log *slog.Logge
if err != nil {
return nil, fmt.Errorf("getting SNP validate options: %w", err)
}
for _, opt := range opts {
for i, opt := range opts {
opt.ValidateOpts.HostData = coordinatorPolicyChecksum
name := fmt.Sprintf("snp-%d-%s", i, strings.TrimPrefix(opt.VerifyOpts.Product.Name.String(), "SEV_PRODUCT_"))
validators = append(validators, snp.NewValidator(opt.VerifyOpts, opt.ValidateOpts,
logger.NewWithAttrs(logger.NewNamed(log, "validator"), map[string]string{"tee-type": "snp"}),
logger.NewWithAttrs(logger.NewNamed(log, "validator"), map[string]string{"reference-values": name}), name,
))
}

Expand All @@ -44,9 +46,10 @@ func ValidatorsFromManifest(kdsDir string, m *manifest.Manifest, log *slog.Logge
}
var mrConfigID [48]byte
copy(mrConfigID[:], coordinatorPolicyChecksum)
for _, opt := range tdxOpts {
for i, opt := range tdxOpts {
name := fmt.Sprintf("tdx-%d", i)
opt.TdQuoteBodyOptions.MrConfigID = mrConfigID[:]
validators = append(validators, tdx.NewValidator(&tdx.StaticValidateOptsGenerator{Opts: opt}, logger.NewWithAttrs(logger.NewNamed(log, "validator"), map[string]string{"tee-type": "tdx"})))
validators = append(validators, tdx.NewValidator(&tdx.StaticValidateOptsGenerator{Opts: opt}, logger.NewWithAttrs(logger.NewNamed(log, "validator"), map[string]string{"reference-values": name}), name))
}

return validators, nil
Expand Down

0 comments on commit 4e7c967

Please sign in to comment.