-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
attestation: add name to Validator as unique identifier #1095
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -9,6 +9,8 @@ import ( | |||||
"fmt" | ||||||
"log/slog" | ||||||
"net" | ||||||
"strconv" | ||||||
"strings" | ||||||
"time" | ||||||
|
||||||
"github.com/edgelesssys/contrast/internal/atls" | ||||||
|
@@ -86,10 +88,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 := "snp-" + strconv.Itoa(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"}), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that we have a name in the constructor, we could remove the attrs here and add them there? |
||||||
&authInfo) | ||||||
&authInfo, name) | ||||||
validators = append(validators, validator) | ||||||
} | ||||||
|
||||||
|
@@ -98,9 +101,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 := "tdx" + strconv.Itoa(i) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
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{"tee-type": "tdx"}), &authInfo, name)) | ||||||
} | ||||||
|
||||||
serverCfg, err := atls.CreateAttestationServerTLSConfig(c.issuer, validators, c.attestationFailuresCounter) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import ( | |
"crypto/x509/pkix" | ||
"encoding/asn1" | ||
"encoding/base64" | ||
"encoding/hex" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
@@ -94,6 +95,7 @@ type Issuer interface { | |
type Validator interface { | ||
Getter | ||
Validate(attDoc []byte, nonce []byte, peerPublicKey []byte) error | ||
Name() string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More idiomatic might be to implement |
||
} | ||
|
||
// getATLSConfigForClientFunc returns a config setup function that is called once for every client connecting to the server. | ||
|
@@ -233,7 +235,7 @@ func verifyEmbeddedReport(validators []Validator, cert *x509.Certificate, peerPu | |
|
||
// We have a valid attestation document. Let's check it against all applicable validators. | ||
foundExtension = true | ||
for _, validator := range validators { | ||
for i, validator := range validators { | ||
// Optimization: Skip the validator if it doesn't match the attestation type of the document. | ||
if !ex.Id.Equal(validator.OID()) { | ||
continue | ||
|
@@ -248,7 +250,13 @@ 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)) | ||
// The joined error should reveal the atls nonce once to maintain readability. Because the error is only revealed if all validators fail, | ||
// we can implicitly include the nonce in the first validator error and the concatenate the other errors. | ||
Comment on lines
+253
to
+254
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would make more sense to first collect the errors with |
||
if i == 0 { | ||
retErr = errors.Join(retErr, fmt.Errorf("AtlsConnectionNonce: %s || validator %s failed: %w ||", hex.EncodeToString(nonce), validator.Name(), validationErr)) | ||
} else { | ||
retErr = errors.Join(retErr, fmt.Errorf(" validator %s failed: %w ||", validator.Name(), validationErr)) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -439,6 +447,11 @@ func (v FakeValidator) Validate(attDoc []byte, nonce []byte, _ []byte) error { | |
return v.err | ||
} | ||
|
||
// Name returns the name of the validator. | ||
func (v *FakeValidator) Name() string { | ||
return "" | ||
} | ||
|
||
// FakeAttestationDoc is a fake attestation document used for testing. | ||
type FakeAttestationDoc struct { | ||
UserData []byte | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 root OID for the raw SNP report extension used by the validator. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm. I'd say it's technically a node, but not the root node. |
||
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)) | ||
} | ||
}() | ||
|
||
|
@@ -99,6 +102,11 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte, peerPublicKey []byt | |
return nil | ||
} | ||
|
||
// Name returns the name of the validator. | ||
func (v *Validator) Name() string { | ||
return v.name | ||
} | ||
|
||
type snpReport struct { | ||
report *sevsnp.Report | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ package sdk | |
import ( | ||
"fmt" | ||
"log/slog" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/edgelesssys/contrast/internal/atls" | ||
"github.com/edgelesssys/contrast/internal/attestation/certcache" | ||
|
@@ -31,10 +33,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 := "snp-" + strconv.Itoa(i) + "-" + strings.TrimPrefix(opt.VerifyOpts.Product.Name.String(), "SEV_PRODUCT_") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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{"tee-type": "snp"}), name, | ||
)) | ||
} | ||
|
||
|
@@ -44,9 +47,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 := "tdx-" + strconv.Itoa(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{"tee-type": "tdx"}), name)) | ||
} | ||
|
||
return validators, nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.