Skip to content

Commit

Permalink
Allow specifying accepted avisories for SWHardeningNeeded TCB status
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
  • Loading branch information
daniel-weisse committed Sep 26, 2024
1 parent 94226a0 commit 152c8b3
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 14 deletions.
5 changes: 5 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func VerifyCoordinator(ctx context.Context, endpoint string, opts VerifyOptions)
Debug: opts.Debug,
Nonce: opts.Nonce,
AcceptedTCBStatuses: opts.AcceptedTCBStatuses,
AcceptedAdvisories: opts.AcceptedAdvisories,
}); err != nil {
return nil, nil, nil, fmt.Errorf("verifying Coordinator quote: %w", err)
}
Expand Down Expand Up @@ -467,6 +468,10 @@ type VerifyOptions struct {
// If not set, defaults to ["UpToDate", "SWHardeningNeeded"].
// If the Coordinator returns a TCB status not listed, an [attestation.TCBStatusError] is returned.
AcceptedTCBStatuses []string `json:"AcceptedTCBStatuses"`
// AcceptedAdvisories is a list of Intel Security Advisories that are acceptable.
// If the Coordinator returns TCB status "SWHardeningNeeded", the list of advisories for that report must be a subset of this list.
// If not set, all advisories are accepted.
AcceptedAdvisories []string `json:"AcceptedAdvisories"`

// Nonce is an optional, user-defined nonce to be included in the Coordinator's attestation statement.
// If set, the Coordinator will generate an SGX quote over sha256(Coordinator_root_cert, Nonce).
Expand Down
22 changes: 17 additions & 5 deletions api/attestation/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,22 @@ import (
type TCBStatusError struct {
// TCBStatus is the TCB status of the Coordinator enclave.
TCBStatus tcbstatus.Status
// Advisories is a list of Intel Security Advisories if the TCB status is SWHardeningNeeded.
Advisories []string
}

// NewTCBStatusError creates a new TCBStatusError.
func NewTCBStatusError(tcbStatus tcbstatus.Status) error {
return &TCBStatusError{TCBStatus: tcbStatus}
func NewTCBStatusError(tcbStatus tcbstatus.Status, advisories []string) error {
return &TCBStatusError{TCBStatus: tcbStatus, Advisories: advisories}
}

// Error returns the error message.
func (e *TCBStatusError) Error() string {
return fmt.Sprintf("invalid TCB status: %s", e.TCBStatus)
var advisoryMsg string
if len(e.Advisories) > 0 {
advisoryMsg = fmt.Sprintf(": advisories not accepted by configuration: %s", e.Advisories)
}
return fmt.Sprintf("invalid TCB status: %s%s", e.TCBStatus, advisoryMsg)
}

// Config is the expected attestation metadata of a MarbleRun Coordinator enclave.
Expand All @@ -48,6 +54,7 @@ type Config struct {
Debug bool
Nonce []byte
AcceptedTCBStatuses []string
AcceptedAdvisories []string
}

// VerifyCertificate verifies the Coordinator's TLS certificate against the Coordinator's SGX quote.
Expand All @@ -71,8 +78,13 @@ func verifyCertificate(

validity, err := tcb.CheckStatus(report.TCBStatus, quoteErr, config.AcceptedTCBStatuses)
if err != nil {
return NewTCBStatusError(report.TCBStatus)
return NewTCBStatusError(report.TCBStatus, report.TCBAdvisories)
}

if notAccepted := tcb.CheckAdvisories(report.TCBStatus, report.TCBAdvisories, config.AcceptedAdvisories); len(notAccepted) > 0 {
return NewTCBStatusError(report.TCBStatus, notAccepted)
}

switch validity {
case tcb.ValidityUnconditional:
case tcb.ValidityConditional:
Expand All @@ -83,7 +95,7 @@ func verifyCertificate(

if validity != tcb.ValidityUnconditional {
if report.TCBAdvisoriesErr != nil {
fmt.Fprintln(out, "Error: TCB Advisories:", err)
fmt.Fprintln(out, "Error: TCB Advisories:", report.TCBAdvisoriesErr)
} else {
fmt.Fprintln(out, "TCB Advisories:", report.TCBAdvisories)
}
Expand Down
52 changes: 52 additions & 0 deletions api/attestation/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,58 @@ func TestVerifyCertificate(t *testing.T) {
}, attestation.ErrTCBLevelInvalid
},
},
"tcb error with advisories": {
config: defaultConfig,
verify: func([]byte) (attestation.Report, error) {
return attestation.Report{
Data: quoteData[:],
SecurityVersion: 2,
ProductID: []byte{0x03, 0x00},
SignerID: []byte{0xAB, 0xCD},
TCBStatus: tcbstatus.SWHardeningNeeded,
TCBAdvisories: []string{"INTEL-SA-0001"},
}, attestation.ErrTCBLevelInvalid
},
wantErr: true,
wantTCBErr: true,
},
"tcb error with advisories rejected": {
config: func() Config {
config := defaultConfig
config.AcceptedAdvisories = []string{"INTEL-SA-0002"}
return config
}(),
verify: func([]byte) (attestation.Report, error) {
return attestation.Report{
Data: quoteData[:],
SecurityVersion: 2,
ProductID: []byte{0x03, 0x00},
SignerID: []byte{0xAB, 0xCD},
TCBStatus: tcbstatus.SWHardeningNeeded,
TCBAdvisories: []string{"INTEL-SA-0001"},
}, attestation.ErrTCBLevelInvalid
},
wantErr: true,
wantTCBErr: true,
},
"tcb error with advisories accepted": {
config: func() Config {
config := defaultConfig
config.AcceptedTCBStatuses = []string{"SWHardeningNeeded"}
config.AcceptedAdvisories = []string{"INTEL-SA-0001"}
return config
}(),
verify: func([]byte) (attestation.Report, error) {
return attestation.Report{
Data: quoteData[:],
SecurityVersion: 2,
ProductID: []byte{0x03, 0x00},
SignerID: []byte{0xAB, 0xCD},
TCBStatus: tcbstatus.SWHardeningNeeded,
TCBAdvisories: []string{"INTEL-SA-0001"},
}, attestation.ErrTCBLevelInvalid
},
},
}

for name, tc := range testCases {
Expand Down
1 change: 1 addition & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ To install and configure MarbleRun, run:
rootCmd.PersistentFlags().String("era-config", "", "Path to a remote-attestation config file in JSON format. If none is provided, the command attempts to use './coordinator-era.json'. If that does not exist, the command will attempt to load a matching config file from the MarbleRun GitHub repository")
rootCmd.PersistentFlags().BoolP("insecure", "i", false, "Set to skip quote verification, needed when running in simulation mode")
rootCmd.PersistentFlags().StringSlice("accepted-tcb-statuses", []string{"UpToDate", "SWHardeningNeeded"}, "Comma-separated list of user accepted TCB statuses")
rootCmd.PersistentFlags().StringSlice("accepted-advisories", nil, "Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted")
rootCmd.PersistentFlags().StringP("namespace", "n", helm.Namespace, "Kubernetes namespace of the MarbleRun installation")
rootCmd.PersistentFlags().String("nonce", "", "(Optional) nonce to use for quote verification. If set, the Coordinator will generate a quote over sha256(CoordinatorCert + nonce)")
rootCmd.PersistentFlags().String("save-sgx-quote", "", "If set, save the Coordinator's SGX quote to the specified file")
Expand Down
5 changes: 5 additions & 0 deletions cli/internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func parseRestFlags(cmd *cobra.Command) (api.VerifyOptions, string, error) {
if err != nil {
return api.VerifyOptions{}, "", err
}
acceptedAdvisories, err := cmd.Flags().GetStringSlice("accepted-advisories")
if err != nil {
return api.VerifyOptions{}, "", err
}
k8sNamespace, err := cmd.Flags().GetString("namespace")
if err != nil {
return api.VerifyOptions{}, "", err
Expand Down Expand Up @@ -83,6 +87,7 @@ func parseRestFlags(cmd *cobra.Command) (api.VerifyOptions, string, error) {
}
}
verifyOptions.AcceptedTCBStatuses = acceptedTCBStatuses
verifyOptions.AcceptedAdvisories = acceptedAdvisories
verifyOptions.Nonce = []byte(nonce)

return verifyOptions, sgxQuotePath, nil
Expand Down
4 changes: 4 additions & 0 deletions coordinator/quote/ert.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ type PackageProperties struct {
SecurityVersion *uint
// AcceptedTCBStatuses is a list of TCB levels an enclave is allowed to have.
AcceptedTCBStatuses []string
// AcceptedAdvisories is a list of open Intel Security Advisories an enclave is allowed to run on,
// when it reports an SWHardeningNeeded TCB status.
// An empty list allows all advisories.
AcceptedAdvisories []string
}

// InfrastructureProperties contains the infrastructure-specific properties of a SGX DCAP quote.
Expand Down
4 changes: 4 additions & 0 deletions coordinator/quote/ertvalidator/ertvalidator.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func (v *ERTValidator) Validate(givenQuote []byte, cert []byte, pp quote.Package
v.log.Error("TCB Advisories", zap.Error(report.TCBAdvisoriesErr))
}

if notAccepted := tcb.CheckAdvisories(report.TCBStatus, report.TCBAdvisories, pp.AcceptedAdvisories); len(notAccepted) > 0 {
return fmt.Errorf("TCB status %s contains advisories not accepted by configuration: %s", report.TCBStatus, notAccepted)
}

switch validity {
case tcb.ValidityUnconditional:
case tcb.ValidityConditional:
Expand Down
Loading

0 comments on commit 152c8b3

Please sign in to comment.