diff --git a/internal/attestation/aws/snp/errors.go b/internal/attestation/aws/snp/errors.go index 2960455f911..2b07870b7d7 100644 --- a/internal/attestation/aws/snp/errors.go +++ b/internal/attestation/aws/snp/errors.go @@ -20,7 +20,7 @@ func newDecodeError(err error) *decodeError { } func (e *decodeError) Error() string { - return fmt.Sprintf("error decoding public key: %v", e.inner) + return fmt.Sprintf("decoding public key: %v", e.inner) } func (e *decodeError) Unwrap() error { diff --git a/internal/attestation/aws/snp/issuer.go b/internal/attestation/aws/snp/issuer.go index 089d3ba23a0..07e4e295fd5 100644 --- a/internal/attestation/aws/snp/issuer.go +++ b/internal/attestation/aws/snp/issuer.go @@ -48,7 +48,7 @@ func NewIssuer(log attestation.Logger) *Issuer { func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) { tpmAk, err := client.AttestationKeyRSA(tpm) if err != nil { - return nil, fmt.Errorf("error creating RSA Endorsement key: %w", err) + return nil, fmt.Errorf("creating RSA Endorsement key: %w", err) } return tpmAk, nil @@ -60,7 +60,7 @@ func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) { func getInstanceInfo(_ context.Context, tpm io.ReadWriteCloser, _ []byte) ([]byte, error) { tpmAk, err := client.AttestationKeyRSA(tpm) if err != nil { - return nil, fmt.Errorf("error creating RSA Endorsement key: %w", err) + return nil, fmt.Errorf("creating RSA Endorsement key: %w", err) } encoded, err := x509.MarshalPKIXPublicKey(tpmAk.PublicKey()) diff --git a/internal/attestation/aws/snp/testdata/testdata.go b/internal/attestation/aws/snp/testdata/testdata.go index 27ec890c609..61d14f1549a 100644 --- a/internal/attestation/aws/snp/testdata/testdata.go +++ b/internal/attestation/aws/snp/testdata/testdata.go @@ -14,7 +14,10 @@ import _ "embed" //go:embed report.txt var SNPReport string -// Valid VLEK for SNPReport. +// AKDigest holds the AK digest embedded in SNPReport.REPORT_DATA. +const AKDigest = "032635613c8e331fa29e096371910fe6a1f69383dda02c9461400a70b66d87a3da5dd863002522be43afc34f2c233989bd6e401e351d10d7cc800d6f5dfcf019" + +// VLEK for SNPReport. // //go:embed vlek.pem var VLEK []byte diff --git a/internal/attestation/aws/snp/validator.go b/internal/attestation/aws/snp/validator.go index 5a4fb79c33d..ee12cde7f21 100644 --- a/internal/attestation/aws/snp/validator.go +++ b/internal/attestation/aws/snp/validator.go @@ -103,12 +103,13 @@ func sha512sum(key crypto.PublicKey) ([64]byte, error) { return sha512.Sum512(pub), nil } -// Validate a given SNP report. +// snpReportValidator validates a given SNP report. type snpReportValidator interface { validate(attestation vtpm.AttestationDocument, ask *x509.Certificate, ark *x509.Certificate, ak [64]byte, config *config.AWSSEVSNP, log attestation.Logger) error } -// Validation logic for the AWS SNP implementation. +// awsValidator implements the validation for AWS SNP attestation. +// The properties exist for unittesting. type awsValidator struct { verifier reportVerifier validator reportValidator @@ -169,6 +170,10 @@ func (a *awsValidator) validate(attestation vtpm.AttestationDocument, ask *x509. }, VMPL: new(int), // Checks that Virtual Machine Privilege Level (VMPL) is 0. // This checks that the reported LaunchTCB version is equal or greater than the minimum specified in the config. + // We don't specify Options.MinimumTCB as it only restricts the allowed TCB for Current_ and Reported_TCB. + // Because we allow Options.ProvisionalFirmware, there is not security gained in also checking Current_ and Reported_TCB. + // We always have to check Launch_TCB as this value indicated the smallest TCB version a VM has seen during + // it's lifetime. MinimumLaunchTCB: kds.TCBParts{ BlSpl: config.BootloaderVersion.Value, // Bootloader TeeSpl: config.TEEVersion.Value, // TEE (Secure OS) diff --git a/internal/attestation/aws/snp/validator_test.go b/internal/attestation/aws/snp/validator_test.go index 28a159b6a93..731f89541cc 100644 --- a/internal/attestation/aws/snp/validator_test.go +++ b/internal/attestation/aws/snp/validator_test.go @@ -35,13 +35,8 @@ import ( "github.com/stretchr/testify/require" ) -const ( - // validAKDigest is the AK hash of the public key embedded in 'reportValid'. - validAKDigest = "032635613c8e331fa29e096371910fe6a1f69383dda02c9461400a70b66d87a3da5dd863002522be43afc34f2c233989bd6e401e351d10d7cc800d6f5dfcf019" -) - func TestGetTrustedKey(t *testing.T) { - validator := &Validator{ask: nil, ark: nil, reportValidator: stubawsValidator{}} + validator := func() *Validator { return &Validator{ask: nil, ark: nil, reportValidator: stubawsValidator{}} } testCases := map[string]struct { akPub []byte info []byte @@ -71,7 +66,7 @@ func TestGetTrustedKey(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) - out, err := validator.getTrustedKey( + out, err := validator().getTrustedKey( context.Background(), vtpm.AttestationDocument{ Attestation: &attest.Attestation{ @@ -105,8 +100,6 @@ func TestValidateSNPReport(t *testing.T) { certs, err := loadCerts(testdata.CertChain) require.NoError(err) ark := certs[1] - certs, err = loadCerts(testdata.CertChain) - require.NoError(err) ask := certs[0] // reportTransformer unpacks the base64 encoded report, applies the given transformations and re-encodes it. @@ -130,13 +123,13 @@ func TestValidateSNPReport(t *testing.T) { wantErr bool }{ "success": { - ak: validAKDigest, + ak: testdata.AKDigest, report: testdata.SNPReport, verifier: &reportVerifierImpl{}, validator: &reportValidatorImpl{}, }, "invalid report data": { - ak: validAKDigest, + ak: testdata.AKDigest, report: reportTransformer(testdata.SNPReport, func(r *spb.Report) { r.ReportData = make([]byte, 64) }), @@ -145,7 +138,7 @@ func TestValidateSNPReport(t *testing.T) { wantErr: true, }, "invalid report signature": { - ak: validAKDigest, + ak: testdata.AKDigest, report: reportTransformer(testdata.SNPReport, func(r *spb.Report) { r.Signature[0]++ }), verifier: &reportVerifierImpl{}, validator: &reportValidatorImpl{}, diff --git a/internal/attestation/snp/snp_test.go b/internal/attestation/snp/snp_test.go index cc43b04e1ce..0179ac05b4f 100644 --- a/internal/attestation/snp/snp_test.go +++ b/internal/attestation/snp/snp_test.go @@ -23,8 +23,6 @@ import ( "github.com/stretchr/testify/require" ) -const vlekReport = "02000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000300000000000ace0300000000000000040000000000000044a93ab043ad14ece9bfa97305d95302c9cc6ed95e17efaf7348ed7a7603e1ca89d12758e089d2abcf5a4dd16a99e3cb4cba8f0b8e8cb8eac3e926f1d2b5cfecc2c84b9364fc9f0f54b04534768c860c6e0e386ad98b96e8b98eca46ac8971d05c531ba48373f054c880cfd1f4a0a84e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c5d6770df734a203cd061a3698e702caed25e7f744dc060eb9dcba0f2e4bdb2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000a7301360100013601000300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b9853dac65f127574c6a578c11885e1887d4c7ae446237d4273715dd8c05cfe4bd49facc1392f2ca7354c8f0d34d65500000000000000000000000000000000000000000000000004013481e9c6a6bb112818aeba3bd178d788dedf62600b8c7892a8d3df4d880265010e7d833201156364a001e62f47b570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - // TestParseCertChain tests the parsing of the certificate chain. func TestParseCertChain(t *testing.T) { defaultCertChain := testdata.CertChain @@ -130,7 +128,7 @@ func TestParseVCEK(t *testing.T) { // TestAttestationWithCerts tests the basic unmarshalling of the attestation report and the ASK / ARK precedence. func TestAttestationWithCerts(t *testing.T) { defaultReport := testdata.AttestationReport - vlekReport, err := hex.DecodeString(vlekReport) + vlekReport, err := hex.DecodeString(testdata.AttestationReportVLEK) require.NoError(t, err) testdataArk, testdataAsk := mustCertChainToPem(t, testdata.CertChain) testdataArvk, testdataAsvk := mustCertChainToPem(t, testdata.VlekCertChain) diff --git a/internal/attestation/snp/testdata/testdata.go b/internal/attestation/snp/testdata/testdata.go index fb1308fb513..c749dd89985 100644 --- a/internal/attestation/snp/testdata/testdata.go +++ b/internal/attestation/snp/testdata/testdata.go @@ -9,11 +9,14 @@ package testdata import _ "embed" -// AttestationBytes is an example attestation report from a Constellation VM. +// AttestationReport is an example attestation report from a Constellation VM. // //go:embed attestation.bin var AttestationReport []byte +// AttestationReportVLEK is an example attestation report signed by a VLEK. +const AttestationReportVLEK = "02000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000300000000000ace0300000000000000040000000000000044a93ab043ad14ece9bfa97305d95302c9cc6ed95e17efaf7348ed7a7603e1ca89d12758e089d2abcf5a4dd16a99e3cb4cba8f0b8e8cb8eac3e926f1d2b5cfecc2c84b9364fc9f0f54b04534768c860c6e0e386ad98b96e8b98eca46ac8971d05c531ba48373f054c880cfd1f4a0a84e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c5d6770df734a203cd061a3698e702caed25e7f744dc060eb9dcba0f2e4bdb2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000a7301360100013601000300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b9853dac65f127574c6a578c11885e1887d4c7ae446237d4273715dd8c05cfe4bd49facc1392f2ca7354c8f0d34d65500000000000000000000000000000000000000000000000004013481e9c6a6bb112818aeba3bd178d788dedf62600b8c7892a8d3df4d880265010e7d833201156364a001e62f47b570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + // AzureThimVCEK is an example VCEK certificate (PEM, as returned from Azure THIM) for the AttestationReport. // //go:embed vcek.pem