From 152c8b38ea838931545f57791c90609fb462c143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Wei=C3=9Fe?= Date: Thu, 26 Sep 2024 12:41:04 +0200 Subject: [PATCH] Allow specifying accepted avisories for SWHardeningNeeded TCB status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Weiße --- api/api.go | 5 ++ api/attestation/attestation.go | 22 +++++-- api/attestation/attestation_test.go | 52 +++++++++++++++++ cli/cmd/root.go | 1 + cli/internal/cmd/cmd.go | 5 ++ coordinator/quote/ert.go | 4 ++ .../quote/ertvalidator/ertvalidator.go | 4 ++ docs/docs/reference/cli.md | 26 +++++++++ docs/docs/workflows/define-manifest.md | 4 ++ internal/tcb/tcb.go | 20 +++++++ internal/tcb/tcb_test.go | 58 ++++++++++++++++--- 11 files changed, 187 insertions(+), 14 deletions(-) diff --git a/api/api.go b/api/api.go index 505ff66e..26f9194d 100644 --- a/api/api.go +++ b/api/api.go @@ -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) } @@ -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). diff --git a/api/attestation/attestation.go b/api/attestation/attestation.go index 08162740..1c6d2440 100644 --- a/api/attestation/attestation.go +++ b/api/attestation/attestation.go @@ -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. @@ -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. @@ -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: @@ -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) } diff --git a/api/attestation/attestation_test.go b/api/attestation/attestation_test.go index cae08018..5003489d 100644 --- a/api/attestation/attestation_test.go +++ b/api/attestation/attestation_test.go @@ -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 { diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 7c36f000..efbb677c 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -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") diff --git a/cli/internal/cmd/cmd.go b/cli/internal/cmd/cmd.go index 0a565d0c..b7eccb60 100644 --- a/cli/internal/cmd/cmd.go +++ b/cli/internal/cmd/cmd.go @@ -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 @@ -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 diff --git a/coordinator/quote/ert.go b/coordinator/quote/ert.go index 9ee4afe4..a994dcfe 100644 --- a/coordinator/quote/ert.go +++ b/coordinator/quote/ert.go @@ -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. diff --git a/coordinator/quote/ertvalidator/ertvalidator.go b/coordinator/quote/ertvalidator/ertvalidator.go index 9ae10697..02f6aaad 100644 --- a/coordinator/quote/ertvalidator/ertvalidator.go +++ b/coordinator/quote/ertvalidator/ertvalidator.go @@ -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: diff --git a/docs/docs/reference/cli.md b/docs/docs/reference/cli.md index 0097b5d6..33888827 100644 --- a/docs/docs/reference/cli.md +++ b/docs/docs/reference/cli.md @@ -81,6 +81,7 @@ marblerun install --dcap-pccs-url https://pccs.example.com/sgx/certification/v4/ ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -112,6 +113,7 @@ marblerun uninstall [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -142,6 +144,7 @@ marblerun precheck [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -173,6 +176,7 @@ marblerun check [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -208,6 +212,7 @@ manifest set manifest.json example.com:4433 [--era-config=config.json] [--insecu ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -249,6 +254,7 @@ marblerun manifest get $MARBLERUN -s --era-config=era.json ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -288,6 +294,7 @@ marblerun manifest log $MARBLERUN ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -325,6 +332,7 @@ marblerun manifest set manifest.json $MARBLERUN --recovery-data=recovery-secret. ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -355,6 +363,7 @@ marblerun manifest signature [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -381,6 +390,7 @@ Manage manifest updates for the MarbleRun Coordinator. ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -422,6 +432,7 @@ marblerun manifest update apply update-manifest.json $MARBLERUN --cert=admin-cer ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -464,6 +475,7 @@ marblerun manifest update acknowledge update-manifest.json $MARBLERUN --cert=adm ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -502,6 +514,7 @@ marblerun manifest update cancel $MARBLERUN --cert=admin-cert.pem --key=admin-ke ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -540,6 +553,7 @@ marblerun manifest update get $MARBLERUN --era-config=era.json ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -576,6 +590,7 @@ marblerun manifest verify manifest.json $MARBLERUN ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -602,6 +617,7 @@ Retrieves the certificate of the MarbleRun Coordinator ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -633,6 +649,7 @@ marblerun certificate root [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -664,6 +681,7 @@ marblerun certificate intermediate [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -695,6 +713,7 @@ marblerun certificate chain [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -725,6 +744,7 @@ Set or retrieve a secret defined in the manifest. ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -773,6 +793,7 @@ marblerun secret set certificate.pem $MARBLERUN -c admin.crt -k admin.key --from ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) -c, --cert string PEM encoded MarbleRun user certificate file (required) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") @@ -816,6 +837,7 @@ marblerun secret get genericSecret symmetricKeyShared $MARBLERUN -c admin.crt -k ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) -c, --cert string PEM encoded MarbleRun user certificate file (required) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") @@ -864,6 +886,7 @@ marblerun status [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -900,6 +923,7 @@ marblerun recover recovery_key_decrypted $MARBLERUN ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -930,6 +954,7 @@ marblerun package-info [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 @@ -960,6 +985,7 @@ marblerun version [flags] ### Options inherited from parent commands ``` + --accepted-advisories strings Comma-separated list of user accepted Intel Security Advisories for SWHardeningNeeded TCB status. If empty, all advisories are accepted --accepted-tcb-statuses strings Comma-separated list of user accepted TCB statuses (default [UpToDate,SWHardeningNeeded]) --coordinator-cert string Path to MarbleRun Coordinator's root certificate to use for TLS connections (default "$HOME/.config/marblerun/coordinator-cert.pem") --era-config string 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 diff --git a/docs/docs/workflows/define-manifest.md b/docs/docs/workflows/define-manifest.md index 6029e350..8cb7f528 100644 --- a/docs/docs/workflows/define-manifest.md +++ b/docs/docs/workflows/define-manifest.md @@ -15,6 +15,7 @@ The `Packages` section of the manifest lists all the secure enclave software pac * `SecurityVersion`: an integer that reflects the security-patch level of the enclave software. Can only be used in conjunction with `SignerID`. * `Debug`: set to `true` if the enclave is to be run in debug mode. This allows you to experiment with deploying your application with MarbleRun without having to worry about setting correct values for the above properties, but note that enclaves in debug mode aren't secure. * `AcceptedTCBStatuses`: a list of acceptable [TCB statuses](https://docs.trustauthority.intel.com/main/articles/concept-platform-tcb.html#attester-tcb-claims) a Marble is allowed to start with. You can use this option to allow Marbles to run on machines whose TCB is out-of-date. If not set, it defaults to `["UpToDate", "SWHardeningNeeded"]`. +* `AcceptedAdivsories`: a list of acceptable [Intel Security Advisories](https://www.intel.com/content/www/us/en/security-center/default.html) when a Marble is allowed to run with an `SWHardeningNeeded` TCB status. If not set, all advisories are allowed. Has no effect if the Marble has a different TCB status from `SWHardeningNeeded`. The following gives an example of a simple `Packages` section with made-up values. @@ -30,6 +31,9 @@ The following gives an example of a simple `Packages` section with made-up value "SWHardeningNeeded", "ConfigurationNeeded", "ConfigurationAndSWHardeningNeeded" + ], + "AcceptedAdvisories": [ + "INTEL-SA-00001" ] }, "frontend": { diff --git a/internal/tcb/tcb.go b/internal/tcb/tcb.go index c31d6404..192b9085 100644 --- a/internal/tcb/tcb.go +++ b/internal/tcb/tcb.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "slices" + "strings" "github.com/edgelesssys/ego/attestation" "github.com/edgelesssys/ego/attestation/tcbstatus" @@ -52,3 +53,22 @@ func CheckStatus(status tcbstatus.Status, tcbErr error, accepted []string) (Vali } return ValidityConditional, nil } + +// CheckAdvisories checks a list of Intel Security Advisories against a list of accepted advisories. +// It returns a list of not accepted advisories if the status is SWHardeningNeeded. +// If acceptedAdvisories is empty, all advisories are accepted and this function returns nil. +func CheckAdvisories(status tcbstatus.Status, advisories, acceptedAdvisories []string) []string { + if status != tcbstatus.SWHardeningNeeded || len(acceptedAdvisories) == 0 { + return nil + } + + var notAccepted []string + for _, advisory := range advisories { + if !slices.ContainsFunc(acceptedAdvisories, func(other string) bool { + return strings.EqualFold(advisory, other) + }) { + notAccepted = append(notAccepted, advisory) + } + } + return notAccepted +} diff --git a/internal/tcb/tcb_test.go b/internal/tcb/tcb_test.go index 6f9f1e74..302a8bbc 100644 --- a/internal/tcb/tcb_test.go +++ b/internal/tcb/tcb_test.go @@ -7,7 +7,6 @@ package tcb import ( - "errors" "fmt" "testing" @@ -18,8 +17,6 @@ import ( ) func TestCheckStatus(t *testing.T) { - otherErr := errors.New("failed") - testCases := []struct { status tcbstatus.Status tcbErr error @@ -66,38 +63,38 @@ func TestCheckStatus(t *testing.T) { }, { status: tcbstatus.UpToDate, - tcbErr: otherErr, + tcbErr: assert.AnError, accepted: []string{}, wantErr: true, }, { status: tcbstatus.OutOfDate, - tcbErr: otherErr, + tcbErr: assert.AnError, accepted: []string{}, wantErr: true, }, { status: tcbstatus.SWHardeningNeeded, - tcbErr: otherErr, + tcbErr: assert.AnError, accepted: []string{}, wantErr: true, }, // unexpected error can't be accepted { status: tcbstatus.UpToDate, - tcbErr: otherErr, + tcbErr: assert.AnError, accepted: []string{"UpToDate", "OutOfDate", "SWHardeningNeeded"}, wantErr: true, }, { status: tcbstatus.OutOfDate, - tcbErr: otherErr, + tcbErr: assert.AnError, accepted: []string{"UpToDate", "OutOfDate", "SWHardeningNeeded"}, wantErr: true, }, { status: tcbstatus.SWHardeningNeeded, - tcbErr: otherErr, + tcbErr: assert.AnError, accepted: []string{"UpToDate", "OutOfDate", "SWHardeningNeeded"}, wantErr: true, }, @@ -176,3 +173,46 @@ func TestCheckStatus(t *testing.T) { }) } } + +func TestCheckAdvisories(t *testing.T) { + testCases := map[string]struct { + status tcbstatus.Status + advisories []string + acceptedAdvisories []string + wantNotAccepted []string + }{ + "empty accepted list accepts all advisories": { + status: tcbstatus.SWHardeningNeeded, + advisories: []string{"INTEL-SA-0001", "INTEL-SA-0002"}, + acceptedAdvisories: []string{}, + wantNotAccepted: nil, + }, + "missing accepted advisories": { + status: tcbstatus.SWHardeningNeeded, + advisories: []string{"INTEL-SA-0001", "INTEL-SA-0002"}, + acceptedAdvisories: []string{"INTEL-SA-0003"}, + wantNotAccepted: []string{"INTEL-SA-0001", "INTEL-SA-0002"}, + }, + "all advisories accepted": { + status: tcbstatus.SWHardeningNeeded, + advisories: []string{"INTEL-SA-0001", "INTEL-SA-0002"}, + acceptedAdvisories: []string{"INTEL-SA-0001", "INTEL-SA-0002"}, + wantNotAccepted: nil, + }, + "some advisories accepted": { + status: tcbstatus.SWHardeningNeeded, + advisories: []string{"INTEL-SA-0001", "INTEL-SA-0002"}, + acceptedAdvisories: []string{"INTEL-SA-0001"}, + wantNotAccepted: []string{"INTEL-SA-0002"}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + + notAccepted := CheckAdvisories(tc.status, tc.advisories, tc.acceptedAdvisories) + assert.Equal(tc.wantNotAccepted, notAccepted) + }) + } +}