diff --git a/internal/attestation/simulator/simulator.go b/internal/attestation/simulator/simulator.go index a2cdc88cc..03baabdf5 100644 --- a/internal/attestation/simulator/simulator.go +++ b/internal/attestation/simulator/simulator.go @@ -47,3 +47,7 @@ func (t *simulatedTPM) Close() error { // never close the underlying simulated TPM to allow calling the TPMOpenFunc again return nil } + +func (*simulatedTPM) EventLog() ([]byte, error) { + return nil, nil +} diff --git a/internal/attestation/vtpm/attestation.go b/internal/attestation/vtpm/attestation.go index 8e96a6356..06ac94fe7 100644 --- a/internal/attestation/vtpm/attestation.go +++ b/internal/attestation/vtpm/attestation.go @@ -80,9 +80,8 @@ type AttestationDocument struct { Attestation *attest.Attestation // InstanceInfo is used to verify the provided public key. InstanceInfo []byte - // arbitrary data, signed by the TPM. - UserData []byte - UserDataSignature []byte + // arbitrary data, quoted by the TPM. + UserData []byte } // Issuer handles issuing of TPM based attestation documents. @@ -117,7 +116,8 @@ func (i *Issuer) Issue(userData []byte, nonce []byte) ([]byte, error) { defer aK.Close() // Create an attestation using the loaded key - attestation, err := aK.Attest(tpmClient.AttestOpts{Nonce: nonce}) + extraData := makeExtraData(userData, nonce) + attestation, err := aK.Attest(tpmClient.AttestOpts{Nonce: extraData}) if err != nil { return nil, fmt.Errorf("creating attestation: %w", err) } @@ -128,17 +128,10 @@ func (i *Issuer) Issue(userData []byte, nonce []byte) ([]byte, error) { return nil, fmt.Errorf("fetching instance info: %w", err) } - // Sign user provided data using the loaded key - userDataSigned, err := aK.SignData(userData) - if err != nil { - return nil, fmt.Errorf("signing user data: %w", err) - } - attDoc := AttestationDocument{ - Attestation: attestation, - InstanceInfo: instanceInfo, - UserData: userData, - UserDataSignature: userDataSigned, + Attestation: attestation, + InstanceInfo: instanceInfo, + UserData: userData, } return json.Marshal(attDoc) } @@ -198,7 +191,7 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte) (userData []byte, e if _, err := tpmServer.VerifyAttestation( attDoc.Attestation, tpmServer.VerifyOpts{ - Nonce: nonce, + Nonce: makeExtraData(attDoc.UserData, nonce), TrustedAKs: []crypto.PublicKey{aKP}, AllowSHA1: false, }, @@ -220,12 +213,6 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte) (userData []byte, e } } - // Verify signed user data - digest := sha256.Sum256(attDoc.UserData) - if err = v.verifyUserData(aKP, crypto.SHA256, digest[:], attDoc.UserDataSignature); err != nil { - return nil, fmt.Errorf("verifying signed user data: %w", err) - } - v.log.Infof("Successfully validated attestation document") return attDoc.UserData, nil } @@ -284,6 +271,13 @@ func GetSelectedMeasurements(open TPMOpenFunc, selection tpm2.PCRSelection) (mea return m, nil } +func makeExtraData(userData []byte, nonce []byte) []byte { + data := append([]byte{}, userData...) + data = append(data, nonce...) + digest := sha256.Sum256(data) + return digest[:] +} + // nopAttestationLogger is a no-op implementation of AttestationLogger. type nopAttestationLogger struct{} diff --git a/internal/attestation/vtpm/attestation_test.go b/internal/attestation/vtpm/attestation_test.go index d5c62c894..781e06874 100644 --- a/internal/attestation/vtpm/attestation_test.go +++ b/internal/attestation/vtpm/attestation_test.go @@ -66,13 +66,17 @@ func TestValidate(t *testing.T) { } testExpectedPCRs := measurements.M{ - 0: measurements.WithAllBytes(0x00, true), - 1: measurements.WithAllBytes(0x00, true), + 0: measurements.WithAllBytes(0x00, false), + 1: measurements.WithAllBytes(0x00, false), + uint32(measurements.PCRIndexClusterID): measurements.WithAllBytes(0x00, false), } warnLog := &testAttestationLogger{} - issuer := NewIssuer(newSimTPMWithEventLog, tpmclient.AttestationKeyRSA, fakeGetInstanceInfo) - validator := NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog) + tpmOpen, tpmCloser := tpmsim.NewSimulatedTPMOpenFunc() + defer tpmCloser.Close() + + issuer := NewIssuer(tpmOpen, tpmclient.AttestationKeyRSA, fakeGetInstanceInfo) + validator := NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, nil) nonce := []byte{1, 2, 3, 4} challenge := []byte("Constellation") @@ -90,6 +94,24 @@ func TestValidate(t *testing.T) { require.NoError(err) require.Equal(challenge, out) + // validation must fail after bootstrapping (change of enforced PCR) + require.NoError(MarkNodeAsBootstrapped(tpmOpen, []byte{2})) + attDocBootstrappedRaw, err := issuer.Issue(challenge, nonce) + require.NoError(err) + _, err = validator.Validate(attDocBootstrappedRaw, nonce) + require.Error(err) + + // userData must be bound to PCR state + attDocBootstrappedRaw, err = issuer.Issue([]byte{2, 3}, nonce) + require.NoError(err) + var attDocBootstrapped AttestationDocument + require.NoError(json.Unmarshal(attDocBootstrappedRaw, &attDocBootstrapped)) + attDocBootstrapped.Attestation = attDoc.Attestation + attDocBootstrappedRaw, err = json.Marshal(attDocBootstrapped) + require.NoError(err) + _, err = validator.Validate(attDocBootstrappedRaw, nonce) + require.Error(err) + expectedPCRs := measurements.M{ 0: measurements.WithAllBytes(0x00, true), 1: measurements.WithAllBytes(0x00, true), @@ -128,6 +150,11 @@ func TestValidate(t *testing.T) { nonce []byte wantErr bool }{ + "valid": { + validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog), + attDoc: mustMarshalAttestation(attDoc, require), + nonce: nonce, + }, "invalid nonce": { validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog), attDoc: mustMarshalAttestation(attDoc, require), @@ -137,10 +164,9 @@ func TestValidate(t *testing.T) { "invalid signature": { validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog), attDoc: mustMarshalAttestation(AttestationDocument{ - Attestation: attDoc.Attestation, - InstanceInfo: attDoc.InstanceInfo, - UserData: []byte("wrong data"), - UserDataSignature: attDoc.UserDataSignature, + Attestation: attDoc.Attestation, + InstanceInfo: attDoc.InstanceInfo, + UserData: []byte("wrong data"), }, require), nonce: nonce, wantErr: true, @@ -194,9 +220,8 @@ func TestValidate(t *testing.T) { EventLog: attDoc.Attestation.EventLog, InstanceInfo: attDoc.Attestation.InstanceInfo, }, - InstanceInfo: attDoc.InstanceInfo, - UserData: attDoc.UserData, - UserDataSignature: attDoc.UserDataSignature, + InstanceInfo: attDoc.InstanceInfo, + UserData: attDoc.UserData, }, require), nonce: nonce, wantErr: true,