mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-12 07:59:29 -05:00
Coordinator vTPM: add method to check for previous node initialization
Signed-off-by: Malte Poll <mp@edgeless.systems>
This commit is contained in:
parent
af1aca4b34
commit
be004c971d
@ -1,6 +1,9 @@
|
|||||||
package vtpm
|
package vtpm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/go-tpm/tpm2"
|
"github.com/google/go-tpm/tpm2"
|
||||||
"github.com/google/go-tpm/tpmutil"
|
"github.com/google/go-tpm/tpmutil"
|
||||||
)
|
)
|
||||||
@ -29,3 +32,57 @@ func MarkNodeAsInitialized(openTPM TPMOpenFunc, ownerID, clusterID []byte) error
|
|||||||
// clusterID is used to uniquely identify this running instance of Constellation
|
// clusterID is used to uniquely identify this running instance of Constellation
|
||||||
return tpm2.PCREvent(tpm, PCRIndexClusterID, clusterID)
|
return tpm2.PCREvent(tpm, PCRIndexClusterID, clusterID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNodeInitialized checks if a node is already initialized by reading PCRs.
|
||||||
|
func IsNodeInitialized(openTPM TPMOpenFunc) (bool, error) {
|
||||||
|
tpm, err := openTPM()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer tpm.Close()
|
||||||
|
|
||||||
|
idxOwner := int(PCRIndexOwnerID)
|
||||||
|
idxCluster := int(PCRIndexClusterID)
|
||||||
|
selection := tpm2.PCRSelection{
|
||||||
|
Hash: tpm2.AlgSHA256,
|
||||||
|
PCRs: []int{idxOwner, idxCluster},
|
||||||
|
}
|
||||||
|
|
||||||
|
pcrs, err := tpm2.ReadPCRs(tpm, selection)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pcrs[idxOwner]) == 0 {
|
||||||
|
return false, errors.New("owner ID PCR does not exist")
|
||||||
|
}
|
||||||
|
if len(pcrs[idxCluster]) == 0 {
|
||||||
|
return false, errors.New("cluster ID PCR does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
ownerInitialized := pcrInitialized(pcrs[idxOwner])
|
||||||
|
clusterInitialized := pcrInitialized(pcrs[idxCluster])
|
||||||
|
|
||||||
|
if ownerInitialized == clusterInitialized {
|
||||||
|
return ownerInitialized && clusterInitialized, nil
|
||||||
|
}
|
||||||
|
ownerState := "not initialized"
|
||||||
|
if ownerInitialized {
|
||||||
|
ownerState = "initialized"
|
||||||
|
}
|
||||||
|
clusterState := "not initialized"
|
||||||
|
if clusterInitialized {
|
||||||
|
clusterState = "initialized"
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("PCRs %v and %v are not consistent: PCR[%v]=%v (%v), PCR[%v]=%v (%v)", idxOwner, idxCluster, idxOwner, pcrs[idxOwner], ownerState, idxCluster, pcrs[idxCluster], clusterState)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pcrInitialized checks if a PCR value is set to a non-zero value.
|
||||||
|
func pcrInitialized(pcr []byte) bool {
|
||||||
|
for _, b := range pcr {
|
||||||
|
if b != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-tpm-tools/client"
|
"github.com/google/go-tpm-tools/client"
|
||||||
|
"github.com/google/go-tpm/tpm2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -47,3 +48,52 @@ func TestFailOpener(t *testing.T) {
|
|||||||
|
|
||||||
assert.Error(MarkNodeAsInitialized(func() (io.ReadWriteCloser, error) { return nil, errors.New("failed") }, []byte{0x0, 0x1, 0x2, 0x3}, []byte{0x0, 0x1, 0x2, 0x3}))
|
assert.Error(MarkNodeAsInitialized(func() (io.ReadWriteCloser, error) { return nil, errors.New("failed") }, []byte{0x0, 0x1, 0x2, 0x3}, []byte{0x0, 0x1, 0x2, 0x3}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsNodeInitialized(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
pcrValueOwnerID []byte
|
||||||
|
pcrValueClusterID []byte
|
||||||
|
expectInitialized bool
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
"uninitialized PCRs results in uninitialized node": {},
|
||||||
|
"initializing PCRs result in initialized node": {
|
||||||
|
pcrValueOwnerID: []byte{0x0, 0x1, 0x2, 0x3},
|
||||||
|
pcrValueClusterID: []byte{0x4, 0x5, 0x6, 0x7},
|
||||||
|
expectInitialized: true,
|
||||||
|
},
|
||||||
|
"initializing ownerID alone fails": {
|
||||||
|
pcrValueOwnerID: []byte{0x0, 0x1, 0x2, 0x3},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
"initializing clusterID alone fails": {
|
||||||
|
pcrValueClusterID: []byte{0x4, 0x5, 0x6, 0x7},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
tpm, err := OpenSimulatedTPM()
|
||||||
|
require.NoError(err)
|
||||||
|
defer tpm.Close()
|
||||||
|
if tc.pcrValueOwnerID != nil {
|
||||||
|
require.NoError(tpm2.PCREvent(tpm, PCRIndexOwnerID, tc.pcrValueOwnerID))
|
||||||
|
}
|
||||||
|
if tc.pcrValueClusterID != nil {
|
||||||
|
require.NoError(tpm2.PCREvent(tpm, PCRIndexClusterID, tc.pcrValueClusterID))
|
||||||
|
}
|
||||||
|
initialized, err := IsNodeInitialized(func() (io.ReadWriteCloser, error) {
|
||||||
|
return &simTPMNOPCloser{tpm}, nil
|
||||||
|
})
|
||||||
|
if tc.expectErr {
|
||||||
|
assert.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(err)
|
||||||
|
require.Equal(tc.expectInitialized, initialized)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user