AB#2350: Configurably enforce idkeydigest on Azure

* Add join-config entry for "enforceIdKeyDigest" bool
* Add join-config entry for "idkeydigest"
* Initially filled with TPM value from bootstrapper
* Add config entries for idkeydigest and enforceIdKeyDigest
* Extend azure attestation validator to check idkeydigest,
if configured.
* Update unittests
* Add logger to NewValidator for all CSPs
* Add csp to Updateable type

Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>
Co-authored-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Otto Bittner 2022-08-29 16:41:09 +02:00
parent c84e44913b
commit 4adc19b7f5
31 changed files with 350 additions and 136 deletions

View file

@ -2,8 +2,10 @@ package watcher
import (
"encoding/asn1"
"encoding/hex"
"fmt"
"path/filepath"
"strconv"
"sync"
"github.com/edgelesssys/constellation/internal/atls"
@ -22,6 +24,7 @@ type Updatable struct {
mux sync.Mutex
newValidator newValidatorFunc
fileHandler file.Handler
csp cloudprovider.Provider
atls.Validator
}
@ -30,11 +33,17 @@ func NewValidator(log *logger.Logger, csp string, fileHandler file.Handler) (*Up
var newValidator newValidatorFunc
switch cloudprovider.FromString(csp) {
case cloudprovider.Azure:
newValidator = func(m map[uint32][]byte, e []uint32) atls.Validator { return azure.NewValidator(m, e) }
newValidator = func(m map[uint32][]byte, e []uint32, idkeydigest []byte, enforceIdKeyDigest bool, log *logger.Logger) atls.Validator {
return azure.NewValidator(m, e, idkeydigest, enforceIdKeyDigest, log)
}
case cloudprovider.GCP:
newValidator = func(m map[uint32][]byte, e []uint32) atls.Validator { return gcp.NewValidator(m, e) }
newValidator = func(m map[uint32][]byte, e []uint32, _ []byte, _ bool, log *logger.Logger) atls.Validator {
return gcp.NewValidator(m, e, log)
}
case cloudprovider.QEMU:
newValidator = func(m map[uint32][]byte, e []uint32) atls.Validator { return qemu.NewValidator(m, e) }
newValidator = func(m map[uint32][]byte, e []uint32, _ []byte, _ bool, log *logger.Logger) atls.Validator {
return qemu.NewValidator(m, e, log)
}
default:
return nil, fmt.Errorf("unknown cloud service provider: %q", csp)
}
@ -43,6 +52,7 @@ func NewValidator(log *logger.Logger, csp string, fileHandler file.Handler) (*Up
log: log,
newValidator: newValidator,
fileHandler: fileHandler,
csp: cloudprovider.FromString(csp),
}
if err := u.Update(); err != nil {
@ -82,10 +92,35 @@ func (u *Updatable) Update() error {
}
u.log.Debugf("Enforced PCRs: %v", enforced)
u.Validator = u.newValidator(measurements, enforced)
u.Validator.AddLogger(u.log)
var idkeydigest []byte
var enforceIdKeyDigest bool
if u.csp == cloudprovider.Azure {
u.log.Infof("Updating encforceIdKeyDigest value")
enforceRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.EnforceIdKeyDigestFilename))
if err != nil {
return err
}
enforceIdKeyDigest, err = strconv.ParseBool(string(enforceRaw))
if err != nil {
return fmt.Errorf("parsing content of EnforceIdKeyDigestFilename: %s: %w", enforceRaw, err)
}
u.log.Debugf("New encforceIdKeyDigest value: %v", enforceIdKeyDigest)
u.log.Infof("Updating expected idkeydigest")
idkeydigestRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.IdKeyDigestFilename))
if err != nil {
return err
}
idkeydigest, err = hex.DecodeString(string(idkeydigestRaw))
if err != nil {
return fmt.Errorf("parsing hexstring: %s: %w", idkeydigestRaw, err)
}
u.log.Debugf("New idkeydigest: %x", idkeydigest)
}
u.Validator = u.newValidator(measurements, enforced, idkeydigest, enforceIdKeyDigest, u.log)
return nil
}
type newValidatorFunc func(measurements map[uint32][]byte, enforcedPCRs []uint32) atls.Validator
type newValidatorFunc func(measurements map[uint32][]byte, enforcedPCRs []uint32, idkeydigest []byte, enforceIdKeyDigest bool, log *logger.Logger) atls.Validator

View file

@ -14,7 +14,6 @@ import (
"testing"
"github.com/edgelesssys/constellation/internal/atls"
"github.com/edgelesssys/constellation/internal/attestation/vtpm"
"github.com/edgelesssys/constellation/internal/constants"
"github.com/edgelesssys/constellation/internal/file"
"github.com/edgelesssys/constellation/internal/logger"
@ -78,6 +77,14 @@ func TestNewUpdateableValidator(t *testing.T) {
filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename),
[]uint32{11},
))
require.NoError(handler.Write(
filepath.Join(constants.ServiceBasePath, constants.IdKeyDigestFilename),
[]byte{},
))
require.NoError(handler.Write(
filepath.Join(constants.ServiceBasePath, constants.EnforceIdKeyDigestFilename),
[]byte("false"),
))
}
_, err := NewValidator(
@ -99,7 +106,7 @@ func TestUpdate(t *testing.T) {
require := require.New(t)
oid := fakeOID{1, 3, 9900, 1}
newValidator := func(m map[uint32][]byte, e []uint32) atls.Validator {
newValidator := func(m map[uint32][]byte, e []uint32, idkeydigest []byte, enforceIdKeyDigest bool, _ *logger.Logger) atls.Validator {
return fakeValidator{fakeOID: oid}
}
handler := file.NewHandler(afero.NewMemMapFs())
@ -126,6 +133,14 @@ func TestUpdate(t *testing.T) {
filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename),
[]uint32{11},
))
require.NoError(handler.Write(
filepath.Join(constants.ServiceBasePath, constants.IdKeyDigestFilename),
[]byte{},
))
require.NoError(handler.Write(
filepath.Join(constants.ServiceBasePath, constants.EnforceIdKeyDigestFilename),
[]byte("false"),
))
// call update once to initialize the server's validator
require.NoError(validator.Update())
@ -169,7 +184,7 @@ func TestUpdateConcurrency(t *testing.T) {
validator := &Updatable{
log: logger.NewTest(t),
fileHandler: handler,
newValidator: func(m map[uint32][]byte, e []uint32) atls.Validator {
newValidator: func(m map[uint32][]byte, e []uint32, idkeydigest []byte, enforceIdKeyDigest bool, _ *logger.Logger) atls.Validator {
return fakeValidator{fakeOID: fakeOID{1, 3, 9900, 1}}
},
}
@ -184,6 +199,14 @@ func TestUpdateConcurrency(t *testing.T) {
filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename),
[]uint32{11},
))
require.NoError(handler.Write(
filepath.Join(constants.ServiceBasePath, constants.IdKeyDigestFilename),
[]byte{},
))
require.NoError(handler.Write(
filepath.Join(constants.ServiceBasePath, constants.EnforceIdKeyDigestFilename),
[]byte("false"),
))
var wg sync.WaitGroup
@ -232,8 +255,6 @@ func (v fakeValidator) Validate(attDoc []byte, nonce []byte) ([]byte, error) {
return doc.UserData, v.err
}
func (v fakeValidator) AddLogger(logger vtpm.WarnLogger) {}
type fakeOID asn1.ObjectIdentifier
func (o fakeOID) OID() asn1.ObjectIdentifier {