/* Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ package snp import ( "bytes" "context" "crypto" "crypto/x509" "encoding/hex" "encoding/json" "encoding/pem" "fmt" "io" "net/http" "strings" "testing" "github.com/edgelesssys/constellation/v2/internal/attestation/vtpm" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/google/go-tpm-tools/proto/attest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const ( // askPEM is a PEM encoded AMD signing key. askPEM = `-----BEGIN CERTIFICATE----- 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 0YPk -----END CERTIFICATE----- ` // certTableValid is a valid cert table from an extended SNP report. It includes a valid VLEK. certTableValid = "a8074bc2a25a483eaae639c045a0b8a1300000002b05000000000000000000000000000000000000000000000000000030820527308202d6a003020102020100304606092a864886f70d01010a3039a00f300d06096086480165030402020500a11c301a06092a864886f70d010108300d06096086480165030402020500a203020130a30302010130818031143012060355040b0c0b456e67696e656572696e67310b30090603550406130255533114301206035504070c0b53616e746120436c617261310b300906035504080c024341311f301d060355040a0c16416476616e636564204d6963726f20446576696365733117301506035504030c0e5345562d564c454b2d4d696c616e301e170d3233303432303138333031365a170d3234303432303138333031365a307a31143012060355040b0c0b456e67696e656572696e67310b30090603550406130255533114301206035504070c0b53616e746120436c617261310b300906035504080c024341311f301d060355040a0c16416476616e636564204d6963726f20446576696365733111300f06035504030c085345562d564c454b3076301006072a8648ce3d020106052b81040022036200049c1a9fd526e4f0abfb3b70bc53136ee75c2f6ffc38fee47790e4e3f1f13b08009db13f086c94f74b13f89c70b3b9d9cb296f1834114904754a3d844a3d7ddab170800912d7d8407e155b389b580ea39f108ce68b56d3321bdfc3414324a852eea381ec3081e9301006092b060104019c7801010403020100301406092b060104019c780102040716054d696c616e3011060a2b060104019c7801030104030201033011060a2b060104019c7801030204030201003011060a2b060104019c7801030404030201003011060a2b060104019c7801030504030201003011060a2b060104019c7801030604030201003011060a2b060104019c7801030704030201003011060a2b060104019c78010303040302010a3011060a2b060104019c780103080403020173302706092b060104019c780105041a1618434e3d63632d746573742e616d617a6f6e6177732e636f6d304606092a864886f70d01010a3039a00f300d06096086480165030402020500a11c301a06092a864886f70d010108300d06096086480165030402020500a203020130a30302010103820201002f5dc1b2c04023b90ef20ed2d791705407f6cbecb5ba9a2fa4354f1bfb4806e7bff976a5f6a2474c29a8e04a898a6a699dba12b0be88bbb4b713696b1e54c6cd946d17d9890ebd0ec68b3446f9f093149e1b57c4470e70ebdb911bb51d8a6f4678e710ca932fa8ed736a209d44656ffaba4447ee2e42b91a787c6049b94dbc2b31fe57f782c06894c9c2b33406e90f329d022c4ef5ed47061f8956d04c28bf47a79dbdb7f08e35a478589dba5cedbd66d3259ef86aecec528ea4889870f18bf900477146338d42749fbf0a6f245326998766cf1bd8449f434a00151ba3c4aa12812032b7c5bac2ac908cd9b9006749257a634356ca92c2a47edf728979174e9fe096ed65137f069bc8866591537b2ff0f8a6527963dfd83a18ea81ee13a3174ae8c5d200bddc8cd2813430e99048175ffc0b9614364f4d0c1278412f47e8dec380196fc6bee27bc8037bfc642ee4b100f11f6ce259b58fb908db2a3cf64f8460bb837aa0f4caaebb7bed22ea85d9984d2b9ccaca736da4bde2cbb1273e5086f63432206274e87adca8030a6a61640d396d2f301b4e29731da2c2ae3b9899bc515e7d1213e7033baec8da466d7b15489746310df8727b55feda3de413b65a1ab6336312ecb59088955533d304caa118bdd24cfdf1c1b15fcfda42cb4c1d86091e1949a6b79b5e8a65aa9ecdc3a5cd2a69ff1970317c11f074fc85fd630d7b34ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // hashValid is the AK hash of the public key embedded in 'reportValid'. hashValid = "44a93ab043ad14ece9bfa97305d95302c9cc6ed95e17efaf7348ed7a7603e1ca89d12758e089d2abcf5a4dd16a99e3cb4cba8f0b8e8cb8eac3e926f1d2b5cfec" // reportValid is a valid SNP report. reportValid = "02000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000300000000000ace0300000000000000040000000000000044a93ab043ad14ece9bfa97305d95302c9cc6ed95e17efaf7348ed7a7603e1ca89d12758e089d2abcf5a4dd16a99e3cb4cba8f0b8e8cb8eac3e926f1d2b5cfecc2c84b9364fc9f0f54b04534768c860c6e0e386ad98b96e8b98eca46ac8971d05c531ba48373f054c880cfd1f4a0a84e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c5d6770df734a203cd061a3698e702caed25e7f744dc060eb9dcba0f2e4bdb2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000a7301360100013601000300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b9853dac65f127574c6a578c11885e1887d4c7ae446237d4273715dd8c05cfe4bd49facc1392f2ca7354c8f0d34d65500000000000000000000000000000000000000000000000004013481e9c6a6bb112818aeba3bd178d788dedf62600b8c7892a8d3df4d880265010e7d833201156364a001e62f47b570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // reportInvalid = reportValid[0x2A0]+1. 673. character in the below string. That address is the start of the signature. reportInvalid = "02000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000300000000000ace0300000000000000040000000000000044a93ab043ad14ece9bfa97305d95302c9cc6ed95e17efaf7348ed7a7603e1ca89d12758e089d2abcf5a4dd16a99e3cb4cba8f0b8e8cb8eac3e926f1d2b5cfecc2c84b9364fc9f0f54b04534768c860c6e0e386ad98b96e8b98eca46ac8971d05c531ba48373f054c880cfd1f4a0a84e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c5d6770df734a203cd061a3698e702cbed25e7f744dc060eb9dcba0f2e4bdb2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000a7301360100013601000300000000000a73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b9853dac65f127574c6a578c11885e1887d4c7ae446237d4273715dd8c05cfe4bd49facc1392f2ca7354c8f0d34d65500000000000000000000000000000000000000000000000004013481e9c6a6bb112818aeba3bd178d788dedf62600b8c7892a8d3df4d880265010e7d833201156364a001e62f47b570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) func TestGetTrustedKey(t *testing.T) { validator := &Validator{ark: nil, kdsClient: nil, reportValidator: stubawsValidator{}} testCases := map[string]struct { akPub []byte info []byte wantErr bool assertCorrectError func(error) }{ "null byte docs": { akPub: []byte{0x00, 0x00, 0x00, 0x00}, info: []byte{0x00, 0x00, 0x00, 0x00}, wantErr: true, assertCorrectError: func(err error) { target := &decodeError{} assert.ErrorAs(t, err, &target) }, }, "nil": { akPub: nil, info: nil, wantErr: true, assertCorrectError: func(err error) { target := &decodeError{} assert.ErrorAs(t, err, &target) }, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) out, err := validator.getTrustedKey( context.Background(), vtpm.AttestationDocument{ Attestation: &attest.Attestation{ AkPub: tc.akPub, }, InstanceInfo: tc.info, }, nil, ) if tc.wantErr { assert.Error(err) tc.assertCorrectError(err) } else { assert.NoError(err) } assert.Nil(out) }) } } func TestGetASK(t *testing.T) { testCases := map[string]struct { client askGetter wantErr bool }{ "success": { client: kdsClient{stubClient{ask: []byte(askPEM)}}, }, "no cert": { client: kdsClient{stubClient{ask: []byte{}}}, wantErr: true, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) ask, err := tc.client.getASK(context.Background()) if tc.wantErr { assert.Error(err) } else { assert.NoError(err) assert.NotNil(ask) } }) } } // TestValidateSNPReport has to setup the following to run ValidateSNPReport: // - parse ARK certificate from constants.go. // - parse cached ASK certificate. // - parse cached SNP report. // - parse cached AK hash. Hash and SNP report have to match. // - parse cache VLEK cert. func TestValidateSNPReport(t *testing.T) { ark, err := loadARK() require.NoError(t, err) testCases := map[string]struct { ak string client kdsClient report string wantErr bool }{ "success": { ak: hashValid, client: kdsClient{stubClient{ask: []byte(askPEM)}}, report: reportValid, }, "fail": { ak: hashValid, client: kdsClient{stubClient{ask: []byte(askPEM)}}, report: reportInvalid, wantErr: true, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) require := require.New(t) info, err := loadInstanceInfo(tc.report, certTableValid) require.NoError(err) hash, err := hex.DecodeString(tc.ak) require.NoError(err) v := awsValidator{} err = v.validate(context.Background(), vtpm.AttestationDocument{InstanceInfo: info}, tc.client, ark, [64]byte(hash)) if tc.wantErr { assert.Error(err) } else { assert.NoError(err) } }) } } func TestSha512sum(t *testing.T) { testCases := map[string]struct { key string hash string match bool }{ "success": { // Generated using: rsa.GenerateKey(rand.Reader, 1024). key: "30819f300d06092a864886f70d010101050003818d0030818902818100d4b2f072a32fa98456eb7f5938e2ff361fb64d698ea91e003d34bfc5374b814c16ba9ae3ec392ef6d48cf79b63067e338aa941219a7bcdf18aa43cd38bbe5567504838a3b1dca482035458853c5a171709dfae9df551815010bdfbc6df733cde84c4f7a5b0591d9cda9db087fb411ee3e2a4f19ad50c8331712ecdc5dd7ce34b0203010001", hash: "2d6fe5ec59d7240b8a4c27c2ff27ba1071105fa50d45543768fcbabf9ee3cb8f8fa0afa51e08e053af30f6d11066ebfd47e75bda5ccc085c115d7e1896f3c62f", match: true, }, "mismatching hash": { key: "30819f300d06092a864886f70d010101050003818d0030818902818100d4b2f072a32fa98456eb7f5938e2ff361fb64d698ea91e003d34bfc5374b814c16ba9ae3ec392ef6d48cf79b63067e338aa941219a7bcdf18aa43cd38bbe5567504838a3b1dca482035458853c5a171709dfae9df551815010bdfbc6df733cde84c4f7a5b0591d9cda9db087fb411ee3e2a4f19ad50c8331712ecdc5dd7ce34b0203010001", hash: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", match: false, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) require := require.New(t) newKey, err := loadKeyFromHex(tc.key) require.NoError(err) // Function under test: hash, err := sha512sum(newKey) assert.NoError(err) expected, err := hex.DecodeString(tc.hash) require.NoError(err) if tc.match { assert.True(bytes.Equal(expected, hash[:]), fmt.Sprintf("expected hash %x, got %x", expected, hash)) } else { assert.False(bytes.Equal(expected, hash[:]), fmt.Sprintf("expected mismatching hashes, got %x", hash)) } }) } } func loadKeyFromHex(key string) (crypto.PublicKey, error) { decoded, err := hex.DecodeString(key) if err != nil { return nil, err } return x509.ParsePKIXPublicKey(decoded) } // loadCachedCertChain loads a valid ARK and ASK from the testdata folder. func loadARK() (*x509.Certificate, error) { // Replacement is needed as the newline chars are not interpreted due to the backticks. Backticks are required for config formatting. tmp := strings.ReplaceAll(constants.AMDRootKey, "\\n", "\n") block, _ := pem.Decode([]byte(tmp)) ark, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, err } return ark, nil } // loadInstanceInfo loads a valid SNP report and VLEK cert from the testdata folder. func loadInstanceInfo(report, certs string) ([]byte, error) { reportDec, err := hex.DecodeString(report) if err != nil { return nil, err } certsDec, err := hex.DecodeString(certs) if err != nil { return nil, err } info := instanceInfo{Report: reportDec, Certs: certsDec} infoRaw, err := json.Marshal(info) if err != nil { return nil, err } return infoRaw, nil } type stubClient struct { ask []byte } func (s stubClient) Do(*http.Request) (*http.Response, error) { return &http.Response{ Body: io.NopCloser(bytes.NewReader(s.ask)), }, nil } type stubawsValidator struct{} func (stubawsValidator) validate(context.Context, vtpm.AttestationDocument, askGetter, *x509.Certificate, [64]byte) error { return nil }