mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
attestation: bind user data to PCR state
This commit is contained in:
parent
5e7dc0d7db
commit
dd7d6334ba
@ -47,3 +47,7 @@ func (t *simulatedTPM) Close() error {
|
|||||||
// never close the underlying simulated TPM to allow calling the TPMOpenFunc again
|
// never close the underlying simulated TPM to allow calling the TPMOpenFunc again
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*simulatedTPM) EventLog() ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -80,9 +80,8 @@ type AttestationDocument struct {
|
|||||||
Attestation *attest.Attestation
|
Attestation *attest.Attestation
|
||||||
// InstanceInfo is used to verify the provided public key.
|
// InstanceInfo is used to verify the provided public key.
|
||||||
InstanceInfo []byte
|
InstanceInfo []byte
|
||||||
// arbitrary data, signed by the TPM.
|
// arbitrary data, quoted by the TPM.
|
||||||
UserData []byte
|
UserData []byte
|
||||||
UserDataSignature []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issuer handles issuing of TPM based attestation documents.
|
// 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()
|
defer aK.Close()
|
||||||
|
|
||||||
// Create an attestation using the loaded key
|
// 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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("creating attestation: %w", err)
|
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)
|
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{
|
attDoc := AttestationDocument{
|
||||||
Attestation: attestation,
|
Attestation: attestation,
|
||||||
InstanceInfo: instanceInfo,
|
InstanceInfo: instanceInfo,
|
||||||
UserData: userData,
|
UserData: userData,
|
||||||
UserDataSignature: userDataSigned,
|
|
||||||
}
|
}
|
||||||
return json.Marshal(attDoc)
|
return json.Marshal(attDoc)
|
||||||
}
|
}
|
||||||
@ -198,7 +191,7 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte) (userData []byte, e
|
|||||||
if _, err := tpmServer.VerifyAttestation(
|
if _, err := tpmServer.VerifyAttestation(
|
||||||
attDoc.Attestation,
|
attDoc.Attestation,
|
||||||
tpmServer.VerifyOpts{
|
tpmServer.VerifyOpts{
|
||||||
Nonce: nonce,
|
Nonce: makeExtraData(attDoc.UserData, nonce),
|
||||||
TrustedAKs: []crypto.PublicKey{aKP},
|
TrustedAKs: []crypto.PublicKey{aKP},
|
||||||
AllowSHA1: false,
|
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")
|
v.log.Infof("Successfully validated attestation document")
|
||||||
return attDoc.UserData, nil
|
return attDoc.UserData, nil
|
||||||
}
|
}
|
||||||
@ -284,6 +271,13 @@ func GetSelectedMeasurements(open TPMOpenFunc, selection tpm2.PCRSelection) (mea
|
|||||||
return m, nil
|
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.
|
// nopAttestationLogger is a no-op implementation of AttestationLogger.
|
||||||
type nopAttestationLogger struct{}
|
type nopAttestationLogger struct{}
|
||||||
|
|
||||||
|
@ -66,13 +66,17 @@ func TestValidate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testExpectedPCRs := measurements.M{
|
testExpectedPCRs := measurements.M{
|
||||||
0: measurements.WithAllBytes(0x00, true),
|
0: measurements.WithAllBytes(0x00, false),
|
||||||
1: measurements.WithAllBytes(0x00, true),
|
1: measurements.WithAllBytes(0x00, false),
|
||||||
|
uint32(measurements.PCRIndexClusterID): measurements.WithAllBytes(0x00, false),
|
||||||
}
|
}
|
||||||
warnLog := &testAttestationLogger{}
|
warnLog := &testAttestationLogger{}
|
||||||
|
|
||||||
issuer := NewIssuer(newSimTPMWithEventLog, tpmclient.AttestationKeyRSA, fakeGetInstanceInfo)
|
tpmOpen, tpmCloser := tpmsim.NewSimulatedTPMOpenFunc()
|
||||||
validator := NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog)
|
defer tpmCloser.Close()
|
||||||
|
|
||||||
|
issuer := NewIssuer(tpmOpen, tpmclient.AttestationKeyRSA, fakeGetInstanceInfo)
|
||||||
|
validator := NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, nil)
|
||||||
|
|
||||||
nonce := []byte{1, 2, 3, 4}
|
nonce := []byte{1, 2, 3, 4}
|
||||||
challenge := []byte("Constellation")
|
challenge := []byte("Constellation")
|
||||||
@ -90,6 +94,24 @@ func TestValidate(t *testing.T) {
|
|||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
require.Equal(challenge, out)
|
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{
|
expectedPCRs := measurements.M{
|
||||||
0: measurements.WithAllBytes(0x00, true),
|
0: measurements.WithAllBytes(0x00, true),
|
||||||
1: measurements.WithAllBytes(0x00, true),
|
1: measurements.WithAllBytes(0x00, true),
|
||||||
@ -128,6 +150,11 @@ func TestValidate(t *testing.T) {
|
|||||||
nonce []byte
|
nonce []byte
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
|
"valid": {
|
||||||
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog),
|
||||||
|
attDoc: mustMarshalAttestation(attDoc, require),
|
||||||
|
nonce: nonce,
|
||||||
|
},
|
||||||
"invalid nonce": {
|
"invalid nonce": {
|
||||||
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog),
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog),
|
||||||
attDoc: mustMarshalAttestation(attDoc, require),
|
attDoc: mustMarshalAttestation(attDoc, require),
|
||||||
@ -137,10 +164,9 @@ func TestValidate(t *testing.T) {
|
|||||||
"invalid signature": {
|
"invalid signature": {
|
||||||
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog),
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, VerifyPKCS1v15, warnLog),
|
||||||
attDoc: mustMarshalAttestation(AttestationDocument{
|
attDoc: mustMarshalAttestation(AttestationDocument{
|
||||||
Attestation: attDoc.Attestation,
|
Attestation: attDoc.Attestation,
|
||||||
InstanceInfo: attDoc.InstanceInfo,
|
InstanceInfo: attDoc.InstanceInfo,
|
||||||
UserData: []byte("wrong data"),
|
UserData: []byte("wrong data"),
|
||||||
UserDataSignature: attDoc.UserDataSignature,
|
|
||||||
}, require),
|
}, require),
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@ -194,9 +220,8 @@ func TestValidate(t *testing.T) {
|
|||||||
EventLog: attDoc.Attestation.EventLog,
|
EventLog: attDoc.Attestation.EventLog,
|
||||||
InstanceInfo: attDoc.Attestation.InstanceInfo,
|
InstanceInfo: attDoc.Attestation.InstanceInfo,
|
||||||
},
|
},
|
||||||
InstanceInfo: attDoc.InstanceInfo,
|
InstanceInfo: attDoc.InstanceInfo,
|
||||||
UserData: attDoc.UserData,
|
UserData: attDoc.UserData,
|
||||||
UserDataSignature: attDoc.UserDataSignature,
|
|
||||||
}, require),
|
}, require),
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user