mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-24 23:19:39 -05:00
attestation: tdx issuer/validator (#1265)
* Add TDX validator * Add TDX issuer --------- Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
d104af6e51
commit
dd2da25ebe
@ -1889,6 +1889,14 @@ def go_dependencies():
|
||||
sum = "h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=",
|
||||
version = "v0.0.0-20230303085714-62ede861d33f",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_edgelesssys_go_tdx_qpl",
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "github.com/edgelesssys/go-tdx-qpl",
|
||||
sum = "h1:uQMmc/B1RGE2VeSsh/NqjRgEheqp1cjy8ELIDTFpaUw=",
|
||||
version = "v0.0.0-20230307140231-bb361f158928",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_edsrzf_mmap_go",
|
||||
@ -6680,6 +6688,15 @@ def go_dependencies():
|
||||
sum = "h1:gpw/0Ku+6RgF3jsi7fnCLmlcikBHfKBCUcu1qgc16OU=",
|
||||
version = "v0.20.3",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_vtolstov_go_ioctl",
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "github.com/vtolstov/go-ioctl",
|
||||
sum = "h1:X6ps8XHfpQjw8dUStzlMi2ybiKQ2Fmdw7UM+TinwvyM=",
|
||||
version = "v0.0.0-20151206205506-6be9cced4810",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_weppos_publicsuffix_go",
|
||||
build_file_generation = "on",
|
||||
|
@ -23,7 +23,9 @@ go_library(
|
||||
"//bootstrapper/internal/nodelock",
|
||||
"//internal/atls",
|
||||
"//internal/attestation/choose",
|
||||
"//internal/attestation/initialize",
|
||||
"//internal/attestation/simulator",
|
||||
"//internal/attestation/tdx",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/cloud/aws",
|
||||
"//internal/cloud/azure",
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/tdx"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
awscloud "github.com/edgelesssys/constellation/v2/internal/cloud/aws"
|
||||
azurecloud "github.com/edgelesssys/constellation/v2/internal/cloud/azure"
|
||||
@ -63,7 +64,7 @@ func main() {
|
||||
var clusterInitJoiner clusterInitJoiner
|
||||
var metadataAPI metadataAPI
|
||||
var cloudLogger logging.CloudLogger
|
||||
var openTPM vtpm.TPMOpenFunc
|
||||
var openDevice vtpm.TPMOpenFunc
|
||||
var fs afero.Fs
|
||||
|
||||
helmClient, err := helm.New(log)
|
||||
@ -97,7 +98,7 @@ func main() {
|
||||
"aws", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.New(),
|
||||
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
||||
)
|
||||
openTPM = vtpm.OpenVTPM
|
||||
openDevice = vtpm.OpenVTPM
|
||||
fs = afero.NewOsFs()
|
||||
|
||||
case cloudprovider.GCP:
|
||||
@ -117,7 +118,7 @@ func main() {
|
||||
"gcp", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.New(),
|
||||
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
||||
)
|
||||
openTPM = vtpm.OpenVTPM
|
||||
openDevice = vtpm.OpenVTPM
|
||||
fs = afero.NewOsFs()
|
||||
log.Infof("Added load balancer IP to routing table")
|
||||
|
||||
@ -136,7 +137,7 @@ func main() {
|
||||
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
||||
)
|
||||
|
||||
openTPM = vtpm.OpenVTPM
|
||||
openDevice = vtpm.OpenVTPM
|
||||
fs = afero.NewOsFs()
|
||||
|
||||
case cloudprovider.QEMU:
|
||||
@ -148,7 +149,16 @@ func main() {
|
||||
)
|
||||
metadataAPI = metadata
|
||||
|
||||
openTPM = vtpm.OpenVTPM
|
||||
switch attestVariant {
|
||||
case variant.QEMUVTPM{}:
|
||||
openDevice = vtpm.OpenVTPM
|
||||
case variant.QEMUTDX{}:
|
||||
openDevice = func() (io.ReadWriteCloser, error) {
|
||||
return tdx.Open()
|
||||
}
|
||||
default:
|
||||
log.Fatalf("Unsupported attestation variant: %s", attestVariant)
|
||||
}
|
||||
fs = afero.NewOsFs()
|
||||
case cloudprovider.OpenStack:
|
||||
cloudLogger = &logging.NopLogger{}
|
||||
@ -162,19 +172,18 @@ func main() {
|
||||
)
|
||||
metadataAPI = metadata
|
||||
|
||||
openTPM = vtpm.OpenVTPM
|
||||
fs = afero.NewOsFs()
|
||||
default:
|
||||
clusterInitJoiner = &clusterFake{}
|
||||
metadataAPI = &providerMetadataFake{}
|
||||
cloudLogger = &logging.NopLogger{}
|
||||
var simulatedTPMCloser io.Closer
|
||||
openTPM, simulatedTPMCloser = simulator.NewSimulatedTPMOpenFunc()
|
||||
openDevice, simulatedTPMCloser = simulator.NewSimulatedTPMOpenFunc()
|
||||
defer simulatedTPMCloser.Close()
|
||||
fs = afero.NewMemMapFs()
|
||||
}
|
||||
|
||||
fileHandler := file.NewHandler(fs)
|
||||
|
||||
run(issuer, openTPM, fileHandler, clusterInitJoiner, metadataAPI, bindIP, bindPort, log, cloudLogger)
|
||||
run(issuer, openDevice, fileHandler, clusterInitJoiner, metadataAPI, bindIP, bindPort, log, cloudLogger)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
|
||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock"
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -25,7 +26,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func run(issuer atls.Issuer, tpm vtpm.TPMOpenFunc, fileHandler file.Handler,
|
||||
func run(issuer atls.Issuer, openDevice vtpm.TPMOpenFunc, fileHandler file.Handler,
|
||||
kube clusterInitJoiner, metadata metadataAPI,
|
||||
bindIP, bindPort string, log *logger.Logger,
|
||||
cloudLogger logging.CloudLogger,
|
||||
@ -44,7 +45,7 @@ func run(issuer atls.Issuer, tpm vtpm.TPMOpenFunc, fileHandler file.Handler,
|
||||
cloudLogger.Disclose("Disk UUID: " + uuid)
|
||||
}
|
||||
|
||||
nodeBootstrapped, err := vtpm.IsNodeBootstrapped(tpm)
|
||||
nodeBootstrapped, err := initialize.IsNodeBootstrapped(openDevice)
|
||||
if err != nil {
|
||||
log.With(zap.Error(err)).Fatalf("Failed to check if node was previously bootstrapped")
|
||||
}
|
||||
@ -56,7 +57,7 @@ func run(issuer atls.Issuer, tpm vtpm.TPMOpenFunc, fileHandler file.Handler,
|
||||
return
|
||||
}
|
||||
|
||||
nodeLock := nodelock.New(tpm)
|
||||
nodeLock := nodelock.New(openDevice)
|
||||
initServer, err := initserver.New(context.Background(), nodeLock, kube, issuer, fileHandler, metadata, log)
|
||||
if err != nil {
|
||||
log.With(zap.Error(err)).Fatalf("Failed to create init server")
|
||||
|
@ -5,5 +5,8 @@ go_library(
|
||||
srcs = ["nodelock.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock",
|
||||
visibility = ["//bootstrapper:__subpackages__"],
|
||||
deps = ["//internal/attestation/vtpm"],
|
||||
deps = [
|
||||
"//internal/attestation/initialize",
|
||||
"//internal/attestation/vtpm",
|
||||
],
|
||||
)
|
||||
|
@ -10,6 +10,7 @@ package nodelock
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
)
|
||||
|
||||
@ -40,5 +41,5 @@ func (l *Lock) TryLockOnce(clusterID []byte) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, vtpm.MarkNodeAsBootstrapped(l.tpm, clusterID)
|
||||
return true, initialize.MarkNodeAsBootstrapped(l.tpm, clusterID)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func updatePCR(m measurements.M, pcrIndex uint32, encoded string) error {
|
||||
oldExpected := m[pcrIndex].Expected
|
||||
expectedPcr := sha256.Sum256(append(oldExpected[:], hashedInput[:]...))
|
||||
m[pcrIndex] = measurements.Measurement{
|
||||
Expected: expectedPcr,
|
||||
Expected: expectedPcr[:],
|
||||
ValidationOpt: m[pcrIndex].ValidationOpt,
|
||||
}
|
||||
return nil
|
||||
|
@ -132,7 +132,7 @@ func TestValidatorUpdateInitPCRs(t *testing.T) {
|
||||
case i == int(measurements.PCRIndexClusterID):
|
||||
pcr, ok := m[uint32(i)]
|
||||
assert.True(ok)
|
||||
assert.Equal(pcrZeroUpdatedOne, pcr.Expected)
|
||||
assert.Equal(pcrZeroUpdatedOne[:], pcr.Expected)
|
||||
|
||||
case i == int(measurements.PCRIndexOwnerID) && tc.ownerID == "":
|
||||
// should be deleted
|
||||
@ -142,7 +142,7 @@ func TestValidatorUpdateInitPCRs(t *testing.T) {
|
||||
case i == int(measurements.PCRIndexOwnerID):
|
||||
pcr, ok := m[uint32(i)]
|
||||
assert.True(ok)
|
||||
assert.Equal(pcrZeroUpdatedOne, pcr.Expected)
|
||||
assert.Equal(pcrZeroUpdatedOne[:], pcr.Expected)
|
||||
|
||||
default:
|
||||
if i >= 17 && i <= 22 {
|
||||
|
@ -69,6 +69,7 @@ go_library(
|
||||
"terraform/openstack/modules/loadbalancer/variables.tf",
|
||||
"terraform/openstack/outputs.tf",
|
||||
"terraform/openstack/variables.tf",
|
||||
"terraform/qemu/modules/instance_group/tdx_domain.xsl",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/terraform",
|
||||
visibility = ["//cli:__subpackages__"],
|
||||
|
@ -82,22 +82,6 @@
|
||||
<xsl:template match="/domain/vcpu">
|
||||
<vcpu placement="static"><xsl:apply-templates select="@*|node()"/></vcpu>
|
||||
</xsl:template>
|
||||
<xsl:template match="/domain/cpu">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="node()|@*"/>
|
||||
<xsl:element name ="topology">
|
||||
<xsl:attribute name="sockets">
|
||||
<xsl:value-of select="'1'"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="cores">
|
||||
<xsl:value-of select="'1'"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="threads">
|
||||
<xsl:value-of select="'1'"/>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template match="/domain/devices/console">
|
||||
<console type="pty">
|
||||
<target type="virtio" port="1" />
|
||||
|
@ -12,6 +12,7 @@ go_library(
|
||||
deps = [
|
||||
"//disk-mapper/internal/systemd",
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/initialize",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/cloud/metadata",
|
||||
"//internal/constants",
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/disk-mapper/internal/systemd"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||
@ -109,7 +110,7 @@ func (s *Manager) PrepareExistingDisk(recover RecoveryDoer) error {
|
||||
}
|
||||
|
||||
// taint the node as initialized
|
||||
if err := vtpm.MarkNodeAsBootstrapped(s.openTPM, clusterID); err != nil {
|
||||
if err := initialize.MarkNodeAsBootstrapped(s.openTPM, clusterID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -70,6 +70,7 @@ require (
|
||||
github.com/docker/docker v23.0.3+incompatible
|
||||
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api v0.0.0
|
||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f
|
||||
github.com/edgelesssys/go-tdx-qpl v0.0.0-20230307140231-bb361f158928
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-playground/locales v0.14.1
|
||||
github.com/go-playground/universal-translator v0.18.1
|
||||
@ -301,6 +302,7 @@ require (
|
||||
github.com/theupdateframework/go-tuf v0.5.2 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.1 // indirect
|
||||
github.com/vtolstov/go-ioctl v0.0.0-20151206205506-6be9cced4810 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -422,6 +422,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=
|
||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f/go.mod h1:hX9gZBSvliJcBEAyrJDh7990hLRg/Is+6PBpDZWSMoc=
|
||||
github.com/edgelesssys/go-tdx-qpl v0.0.0-20230307140231-bb361f158928 h1:uQMmc/B1RGE2VeSsh/NqjRgEheqp1cjy8ELIDTFpaUw=
|
||||
github.com/edgelesssys/go-tdx-qpl v0.0.0-20230307140231-bb361f158928/go.mod h1:IC72qyykUIWl0ZmSk53L4xbLCFDBEGZVaujUmPQOEyw=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
|
||||
@ -1362,6 +1364,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9
|
||||
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vtolstov/go-ioctl v0.0.0-20151206205506-6be9cced4810 h1:X6ps8XHfpQjw8dUStzlMi2ybiKQ2Fmdw7UM+TinwvyM=
|
||||
github.com/vtolstov/go-ioctl v0.0.0-20151206205506-6be9cced4810/go.mod h1:dF0BBJ2YrV1+2eAIyEI+KeSidgA6HqoIP1u5XTlMq/o=
|
||||
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
|
@ -125,6 +125,7 @@ require (
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api v0.0.0 // indirect
|
||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f // indirect
|
||||
github.com/edgelesssys/go-tdx-qpl v0.0.0-20230307140231-bb361f158928 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
@ -259,6 +260,7 @@ require (
|
||||
github.com/theupdateframework/go-tuf v0.5.2 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.1 // indirect
|
||||
github.com/vtolstov/go-ioctl v0.0.0-20151206205506-6be9cced4810 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
|
@ -394,6 +394,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=
|
||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f/go.mod h1:hX9gZBSvliJcBEAyrJDh7990hLRg/Is+6PBpDZWSMoc=
|
||||
github.com/edgelesssys/go-tdx-qpl v0.0.0-20230307140231-bb361f158928 h1:uQMmc/B1RGE2VeSsh/NqjRgEheqp1cjy8ELIDTFpaUw=
|
||||
github.com/edgelesssys/go-tdx-qpl v0.0.0-20230307140231-bb361f158928/go.mod h1:IC72qyykUIWl0ZmSk53L4xbLCFDBEGZVaujUmPQOEyw=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
|
||||
@ -1351,6 +1353,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9
|
||||
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vtolstov/go-ioctl v0.0.0-20151206205506-6be9cced4810 h1:X6ps8XHfpQjw8dUStzlMi2ybiKQ2Fmdw7UM+TinwvyM=
|
||||
github.com/vtolstov/go-ioctl v0.0.0-20151206205506-6be9cced4810/go.mod h1:dF0BBJ2YrV1+2eAIyEI+KeSidgA6HqoIP1u5XTlMq/o=
|
||||
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
|
@ -29,6 +29,9 @@ Attestation code for new platforms needs to implement these two interfaces.
|
||||
package attestation
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||
)
|
||||
|
||||
@ -40,7 +43,47 @@ const (
|
||||
MeasurementSecretContext = "measurementSecret"
|
||||
)
|
||||
|
||||
// Logger is a logger used to print warnings and infos during attestation validation.
|
||||
type Logger interface {
|
||||
Infof(format string, args ...any)
|
||||
Warnf(format string, args ...any)
|
||||
}
|
||||
|
||||
// NOPLogger is a no-op implementation of [Logger].
|
||||
type NOPLogger struct{}
|
||||
|
||||
// Infof is a no-op.
|
||||
func (NOPLogger) Infof(string, ...interface{}) {}
|
||||
|
||||
// Warnf is a no-op.
|
||||
func (NOPLogger) Warnf(string, ...interface{}) {}
|
||||
|
||||
// DeriveClusterID derives the cluster ID from a salt and secret value.
|
||||
func DeriveClusterID(secret, salt []byte) ([]byte, error) {
|
||||
return crypto.DeriveKey(secret, salt, []byte(crypto.DEKPrefix+clusterIDContext), crypto.DerivedKeyLengthDefault)
|
||||
}
|
||||
|
||||
// MakeExtraData binds userData to a random nonce used in attestation.
|
||||
func MakeExtraData(userData []byte, nonce []byte) []byte {
|
||||
data := append([]byte{}, userData...)
|
||||
data = append(data, nonce...)
|
||||
digest := sha256.Sum256(data)
|
||||
return digest[:]
|
||||
}
|
||||
|
||||
// CompareExtraData compares the extra data of a quote with the expected extra data.
|
||||
// Returns true if the data from the quote matches the expected data.
|
||||
// If the slices are not of equal length, the shorter slice is padded with zeros.
|
||||
func CompareExtraData(quoteData, expectedData []byte) bool {
|
||||
if len(quoteData) != len(expectedData) {
|
||||
// If the lengths are not equal, pad the shorter slice with zeros.
|
||||
diff := len(quoteData) - len(expectedData)
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
quoteData = append(quoteData, bytes.Repeat([]byte{0x00}, diff)...)
|
||||
} else {
|
||||
expectedData = append(expectedData, bytes.Repeat([]byte{0x00}, diff)...)
|
||||
}
|
||||
}
|
||||
return bytes.Equal(quoteData, expectedData)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
package attestation
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/crypto/testvector"
|
||||
@ -31,3 +32,48 @@ func TestDeriveClusterID(t *testing.T) {
|
||||
require.NoError(err)
|
||||
assert.NotEqual(clusterID, clusterIDdiff)
|
||||
}
|
||||
|
||||
func TestCompareExtraData(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
ExtraData1 []byte
|
||||
ExtraData2 []byte
|
||||
Expected bool
|
||||
}{
|
||||
"equal": {
|
||||
ExtraData1: bytes.Repeat([]byte{0xAB}, 32),
|
||||
ExtraData2: bytes.Repeat([]byte{0xAB}, 32),
|
||||
Expected: true,
|
||||
},
|
||||
"unequal": {
|
||||
ExtraData1: bytes.Repeat([]byte{0xAB}, 32),
|
||||
ExtraData2: bytes.Repeat([]byte{0xCD}, 32),
|
||||
Expected: false,
|
||||
},
|
||||
"unequal length": {
|
||||
ExtraData1: bytes.Repeat([]byte{0xAB}, 32),
|
||||
ExtraData2: bytes.Repeat([]byte{0xAB}, 64),
|
||||
Expected: false,
|
||||
},
|
||||
"unequal length, padded with 0": {
|
||||
ExtraData1: []byte{0xAB, 0xAB, 0xAB, 0xAB},
|
||||
ExtraData2: []byte{0xAB, 0xAB, 0xAB, 0xAB, 0x00, 0x00, 0x00, 0x00},
|
||||
Expected: true,
|
||||
},
|
||||
"unequal length, prefixed with 0": {
|
||||
ExtraData1: []byte{0x00, 0x00, 0x00, 0x00, 0xAB, 0xAB, 0xAB, 0xAB},
|
||||
ExtraData2: []byte{0xAB, 0xAB, 0xAB, 0xAB},
|
||||
Expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
actual := CompareExtraData(tc.ExtraData1, tc.ExtraData2)
|
||||
assert.Equal(tc.Expected, actual)
|
||||
actual = CompareExtraData(tc.ExtraData2, tc.ExtraData1)
|
||||
assert.Equal(tc.Expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/aws",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
|
||||
@ -28,7 +29,7 @@ type Issuer struct {
|
||||
}
|
||||
|
||||
// NewIssuer creates a new OpenVTPM based issuer for AWS.
|
||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
return &Issuer{
|
||||
Issuer: vtpm.NewIssuer(
|
||||
vtpm.OpenVTPM,
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
awsConfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
@ -30,7 +31,7 @@ type Validator struct {
|
||||
}
|
||||
|
||||
// NewValidator create a new Validator structure and returns it.
|
||||
func NewValidator(cfg *config.AWSNitroTPM, log vtpm.AttestationLogger) *Validator {
|
||||
func NewValidator(cfg *config.AWSNitroTPM, log attestation.Logger) *Validator {
|
||||
v := &Validator{}
|
||||
v.Validator = vtpm.NewValidator(
|
||||
cfg.Measurements,
|
||||
|
@ -14,6 +14,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/idkeydigest",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/cloud/azure",
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||
@ -30,7 +31,7 @@ type Issuer struct {
|
||||
}
|
||||
|
||||
// NewIssuer initializes a new Azure Issuer.
|
||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
i := &Issuer{
|
||||
imds: newIMDSClient(),
|
||||
maa: newMAAClient(),
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
@ -38,11 +39,11 @@ type Validator struct {
|
||||
|
||||
config *config.AzureSEVSNP
|
||||
|
||||
log vtpm.AttestationLogger
|
||||
log attestation.Logger
|
||||
}
|
||||
|
||||
// NewValidator initializes a new Azure validator with the provided PCR values.
|
||||
func NewValidator(cfg *config.AzureSEVSNP, log vtpm.AttestationLogger) *Validator {
|
||||
func NewValidator(cfg *config.AzureSEVSNP, log attestation.Logger) *Validator {
|
||||
if log == nil {
|
||||
log = nopAttestationLogger{}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/trustedlaunch",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/crypto",
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
@ -34,7 +35,7 @@ type Issuer struct {
|
||||
}
|
||||
|
||||
// NewIssuer initializes a new Azure Issuer.
|
||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
i := &Issuer{
|
||||
hClient: &http.Client{},
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
certutil "github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||
@ -35,7 +36,7 @@ type Validator struct {
|
||||
}
|
||||
|
||||
// NewValidator initializes a new Azure validator with the provided PCR values.
|
||||
func NewValidator(cfg *config.AzureTrustedLaunch, log vtpm.AttestationLogger) *Validator {
|
||||
func NewValidator(cfg *config.AzureTrustedLaunch, log attestation.Logger) *Validator {
|
||||
rootPool := x509.NewCertPool()
|
||||
rootPool.AddCert(ameRoot)
|
||||
v := &Validator{roots: rootPool}
|
||||
|
@ -8,12 +8,13 @@ go_library(
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/atls",
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/aws",
|
||||
"//internal/attestation/azure/snp",
|
||||
"//internal/attestation/azure/trustedlaunch",
|
||||
"//internal/attestation/gcp",
|
||||
"//internal/attestation/qemu",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/attestation/tdx",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
],
|
||||
|
@ -10,18 +10,19 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/trustedlaunch"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/gcp"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/tdx"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
)
|
||||
|
||||
// Issuer returns the issuer for the given variant.
|
||||
func Issuer(attestationVariant variant.Variant, log vtpm.AttestationLogger) (atls.Issuer, error) {
|
||||
func Issuer(attestationVariant variant.Variant, log attestation.Logger) (atls.Issuer, error) {
|
||||
switch attestationVariant {
|
||||
case variant.AWSNitroTPM{}:
|
||||
return aws.NewIssuer(log), nil
|
||||
@ -33,6 +34,8 @@ func Issuer(attestationVariant variant.Variant, log vtpm.AttestationLogger) (atl
|
||||
return gcp.NewIssuer(log), nil
|
||||
case variant.QEMUVTPM{}:
|
||||
return qemu.NewIssuer(log), nil
|
||||
case variant.QEMUTDX{}:
|
||||
return tdx.NewIssuer(log), nil
|
||||
case variant.Dummy{}:
|
||||
return atls.NewFakeIssuer(variant.Dummy{}), nil
|
||||
default:
|
||||
@ -41,7 +44,7 @@ func Issuer(attestationVariant variant.Variant, log vtpm.AttestationLogger) (atl
|
||||
}
|
||||
|
||||
// Validator returns the validator for the given variant.
|
||||
func Validator(cfg config.AttestationCfg, log vtpm.AttestationLogger) (atls.Validator, error) {
|
||||
func Validator(cfg config.AttestationCfg, log attestation.Logger) (atls.Validator, error) {
|
||||
switch cfg := cfg.(type) {
|
||||
case *config.AWSNitroTPM:
|
||||
return aws.NewValidator(cfg, log), nil
|
||||
@ -53,6 +56,8 @@ func Validator(cfg config.AttestationCfg, log vtpm.AttestationLogger) (atls.Vali
|
||||
return gcp.NewValidator(cfg, log), nil
|
||||
case *config.QEMUVTPM:
|
||||
return qemu.NewValidator(cfg, log), nil
|
||||
case *config.QEMUTDX:
|
||||
return tdx.NewValidator(cfg, log), nil
|
||||
case *config.DummyCfg:
|
||||
return atls.NewFakeValidator(variant.Dummy{}), nil
|
||||
default:
|
||||
|
@ -11,6 +11,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/gcp",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"io"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
@ -26,7 +27,7 @@ type Issuer struct {
|
||||
}
|
||||
|
||||
// NewIssuer initializes a new GCP Issuer.
|
||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
return &Issuer{
|
||||
Issuer: vtpm.NewIssuer(
|
||||
vtpm.OpenVTPM,
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
|
||||
compute "cloud.google.com/go/compute/apiv1"
|
||||
"cloud.google.com/go/compute/apiv1/computepb"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
@ -35,7 +36,7 @@ type Validator struct {
|
||||
}
|
||||
|
||||
// NewValidator initializes a new GCP validator with the provided PCR values.
|
||||
func NewValidator(cfg *config.GCPSEVES, log vtpm.AttestationLogger) *Validator {
|
||||
func NewValidator(cfg *config.GCPSEVES, log attestation.Logger) *Validator {
|
||||
v := &Validator{
|
||||
restClient: newInstanceClient,
|
||||
}
|
||||
|
29
internal/attestation/initialize/BUILD.bazel
Normal file
29
internal/attestation/initialize/BUILD.bazel
Normal file
@ -0,0 +1,29 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "initialize",
|
||||
srcs = ["initialize.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/initialize",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/tdx",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//tdx",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "initialize_test",
|
||||
srcs = ["initialize_test.go"],
|
||||
embed = [":initialize"],
|
||||
deps = [
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/simulator",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
130
internal/attestation/initialize/initialize.go
Normal file
130
internal/attestation/initialize/initialize.go
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
// Package initialize implements functions to mark a node as initialized in the context of cluster attestation.
|
||||
// This is done by measuring the cluster ID using the available CC technology.
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/tdx"
|
||||
tdxapi "github.com/edgelesssys/go-tdx-qpl/tdx"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// MarkNodeAsBootstrapped marks a node as initialized by extending PCRs.
|
||||
// clusterID is used to uniquely identify this running instance of Constellation.
|
||||
func MarkNodeAsBootstrapped(openDevice func() (io.ReadWriteCloser, error), clusterID []byte) error {
|
||||
device, err := openDevice()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer device.Close()
|
||||
|
||||
// The TDX device is of type *os.File, while the TPM device may be
|
||||
// *os.File or an emulated device over a unix socket.
|
||||
// Therefore, we can't simply use a type switch here,
|
||||
// since the TPM may implement the same methods as the TDX device
|
||||
if handle, ok := tdx.IsTDXDevice(device); ok {
|
||||
return tdxMarkNodeAsBootstrapped(handle, clusterID)
|
||||
}
|
||||
return tpmMarkNodeAsBootstrapped(device, clusterID)
|
||||
}
|
||||
|
||||
// IsNodeBootstrapped checks if a node is already bootstrapped by reading PCRs.
|
||||
func IsNodeBootstrapped(openDevice func() (io.ReadWriteCloser, error)) (bool, error) {
|
||||
device, err := openDevice()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer device.Close()
|
||||
|
||||
// The TDX device is of type *os.File, while the TPM device may be
|
||||
// *os.File or an emulated device over a unix socket.
|
||||
// Therefore, we can't simply use a type switch here,
|
||||
// since the TPM may implement the same methods as the TDX device
|
||||
if handle, ok := tdx.IsTDXDevice(device); ok {
|
||||
return tdxIsNodeBootstrapped(handle)
|
||||
}
|
||||
return tpmIsNodeBootstrapped(device)
|
||||
}
|
||||
|
||||
func tdxIsNodeBootstrapped(handle tdx.Device) (bool, error) {
|
||||
tdMeasure, err := tdxapi.ReadMeasurements(handle)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return measurementInitialized(tdMeasure[measurements.TDXIndexClusterID][:]), nil
|
||||
}
|
||||
|
||||
func tpmIsNodeBootstrapped(tpm io.ReadWriteCloser) (bool, error) {
|
||||
idxClusterID := int(measurements.PCRIndexClusterID)
|
||||
pcrs, err := tpm2.ReadPCRs(tpm, tpm2.PCRSelection{
|
||||
Hash: tpm2.AlgSHA256,
|
||||
PCRs: []int{idxClusterID},
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(pcrs[idxClusterID]) == 0 {
|
||||
return false, errors.New("cluster ID PCR does not exist")
|
||||
}
|
||||
return measurementInitialized(pcrs[idxClusterID]), nil
|
||||
|
||||
/* Old code that will be reenabled in the future
|
||||
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)
|
||||
*/
|
||||
}
|
||||
|
||||
func tdxMarkNodeAsBootstrapped(handle tdx.Device, clusterID []byte) error {
|
||||
return tdxapi.ExtendRTMR(handle, clusterID, measurements.RTMRIndexClusterID)
|
||||
}
|
||||
|
||||
func tpmMarkNodeAsBootstrapped(tpm io.ReadWriteCloser, clusterID []byte) error {
|
||||
return tpm2.PCREvent(tpm, measurements.PCRIndexClusterID, clusterID)
|
||||
}
|
||||
|
||||
// measurementInitialized checks if a PCR value is set to a non-zero value.
|
||||
func measurementInitialized(measurement []byte) bool {
|
||||
return !bytes.Equal(measurement, bytes.Repeat([]byte{0x00}, len(measurement)))
|
||||
}
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package vtpm
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"errors"
|
@ -172,8 +172,8 @@ func verifyWithRekor(ctx context.Context, verifier rekorVerifier, hash string) e
|
||||
|
||||
// byteArrayCompositeLit returns a *ast.CompositeLit representing a byte array literal.
|
||||
// The returned literal is of the form:
|
||||
// [32]byte{ 0x01, 0x02, 0x03, ... }.
|
||||
func byteArrayCompositeLit(hex [32]byte) *ast.CompositeLit {
|
||||
// []byte{ 0x01, 0x02, 0x03, ... }.
|
||||
func byteArrayCompositeLit(hex []byte) *ast.CompositeLit {
|
||||
var elts []ast.Expr
|
||||
// create list of byte literals
|
||||
for _, b := range hex {
|
||||
@ -183,10 +183,9 @@ func byteArrayCompositeLit(hex [32]byte) *ast.CompositeLit {
|
||||
})
|
||||
}
|
||||
// create the composite literal
|
||||
// containing the byte literals as part of an [32]byte array
|
||||
// containing the byte literals as part of an []byte slice
|
||||
return &ast.CompositeLit{
|
||||
Type: &ast.ArrayType{
|
||||
Len: ast.NewIdent("32"),
|
||||
Elt: ast.NewIdent("byte"),
|
||||
},
|
||||
Elts: elts,
|
||||
@ -197,7 +196,7 @@ func byteArrayCompositeLit(hex [32]byte) *ast.CompositeLit {
|
||||
// The returned expression is of the form:
|
||||
//
|
||||
// 0: {
|
||||
// Expected: [32]byte{ 0x01, 0x02, 0x03, ... },
|
||||
// Expected: []byte{ 0x01, 0x02, 0x03, ... },
|
||||
// WarnOnly: false,
|
||||
// },
|
||||
func measurementsEntryKeyValueExpr(pcr uint32, measuremnt measurements.Measurement) *ast.KeyValueExpr {
|
||||
@ -235,11 +234,11 @@ func measurementsEntryKeyValueExpr(pcr uint32, measuremnt measurements.Measureme
|
||||
//
|
||||
// M{
|
||||
// 0: {
|
||||
// Expected: [32]byte{ 0x01, 0x02, 0x03, ... },
|
||||
// Expected: []byte{ 0x01, 0x02, 0x03, ... },
|
||||
// WarnOnly: false,
|
||||
// },
|
||||
// 1: {
|
||||
// Expected: [32]byte{ 0x01, 0x02, 0x03, ... },
|
||||
// Expected: []byte{ 0x01, 0x02, 0x03, ... },
|
||||
// WarnOnly: false,
|
||||
// },
|
||||
// ...
|
||||
|
@ -43,6 +43,12 @@ const (
|
||||
// The value used to extend is derived from Constellation's master key.
|
||||
// TODO: move to stable, non-debug PCR before use.
|
||||
PCRIndexOwnerID = tpmutil.Handle(16)
|
||||
|
||||
// TDXIndexClusterID is the measurement used to mark the node as initialized.
|
||||
// The value is the index of the RTMR + 1, since index 0 of the TDX measurements is reserved for MRTD.
|
||||
TDXIndexClusterID = RTMRIndexClusterID + 1
|
||||
// RTMRIndexClusterID is the RTMR we extend to mark the node as initialized.
|
||||
RTMRIndexClusterID = 2
|
||||
)
|
||||
|
||||
// M are Platform Configuration Register (PCR) values that make up the Measurements.
|
||||
@ -128,7 +134,7 @@ func (m *M) EqualTo(other M) bool {
|
||||
}
|
||||
for k, v := range *m {
|
||||
otherExpected := other[k].Expected
|
||||
if !bytes.Equal(v.Expected[:], otherExpected[:]) {
|
||||
if !bytes.Equal(v.Expected, otherExpected) {
|
||||
return false
|
||||
}
|
||||
if v.ValidationOpt != other[k].ValidationOpt {
|
||||
@ -177,10 +183,45 @@ func (m *M) SetEnforced(enforced []uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals measurements from json.
|
||||
// This function enforces all measurements to be of equal length.
|
||||
func (m *M) UnmarshalJSON(b []byte) error {
|
||||
newM := make(map[uint32]Measurement)
|
||||
if err := json.Unmarshal(b, &newM); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if all measurements are of equal length
|
||||
if err := checkLength(newM); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*m = newM
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML unmarshals measurements from yaml.
|
||||
// This function enforces all measurements to be of equal length.
|
||||
func (m *M) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
newM := make(map[uint32]Measurement)
|
||||
if err := unmarshal(&newM); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if all measurements are of equal length
|
||||
if err := checkLength(newM); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*m = newM
|
||||
return nil
|
||||
}
|
||||
|
||||
// Measurement wraps expected PCR value and whether it is enforced.
|
||||
type Measurement struct {
|
||||
// Expected measurement value.
|
||||
Expected [32]byte `json:"expected" yaml:"expected"`
|
||||
// 32 bytes for vTPM attestation, 48 for TDX.
|
||||
Expected []byte `json:"expected" yaml:"expected"`
|
||||
// ValidationOpt indicates how measurement mismatches should be handled.
|
||||
ValidationOpt MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`
|
||||
}
|
||||
@ -269,11 +310,11 @@ func (m *Measurement) unmarshal(eM encodedMeasurement) error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(expected) != 32 {
|
||||
if len(expected) != 32 && len(expected) != 48 {
|
||||
return fmt.Errorf("invalid measurement: invalid length: %d", len(expected))
|
||||
}
|
||||
|
||||
m.Expected = *(*[32]byte)(expected)
|
||||
m.Expected = expected
|
||||
m.ValidationOpt = eM.WarnOnly
|
||||
|
||||
return nil
|
||||
@ -282,7 +323,7 @@ func (m *Measurement) unmarshal(eM encodedMeasurement) error {
|
||||
// WithAllBytes returns a measurement value where all 32 bytes are set to b.
|
||||
func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement {
|
||||
return Measurement{
|
||||
Expected: *(*[32]byte)(bytes.Repeat([]byte{b}, 32)),
|
||||
Expected: bytes.Repeat([]byte{b}, 32),
|
||||
ValidationOpt: validationOpt,
|
||||
}
|
||||
}
|
||||
@ -290,7 +331,7 @@ func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement
|
||||
// PlaceHolderMeasurement returns a measurement with placeholder values for Expected.
|
||||
func PlaceHolderMeasurement() Measurement {
|
||||
return Measurement{
|
||||
Expected: *(*[32]byte)(bytes.Repeat([]byte{0x12, 0x34}, 16)),
|
||||
Expected: bytes.Repeat([]byte{0x12, 0x34}, 16),
|
||||
ValidationOpt: Enforce,
|
||||
}
|
||||
}
|
||||
@ -316,6 +357,18 @@ func getFromURL(ctx context.Context, client *http.Client, sourceURL *url.URL) ([
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func checkLength(m map[uint32]Measurement) error {
|
||||
var length int
|
||||
for idx, measurement := range m {
|
||||
if length == 0 {
|
||||
length = len(measurement.Expected)
|
||||
} else if len(measurement.Expected) != length {
|
||||
return fmt.Errorf("inconsistent measurement length: index %d: expected %d, got %d", idx, length, len(measurement.Expected))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type encodedMeasurement struct {
|
||||
Expected string `json:"expected" yaml:"expected"`
|
||||
WarnOnly MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`
|
||||
|
@ -16,19 +16,19 @@ import "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
//go:generate measurement-generator
|
||||
|
||||
// DefaultsFor provides the default measurements for given cloud provider.
|
||||
func DefaultsFor(provider cloudprovider.Provider) M {
|
||||
func DefaultsFor(attestationVariant variant.Variant) M {
|
||||
switch provider {
|
||||
case cloudprovider.AWS:
|
||||
return M{0: {Expected: [32]byte{0x73, 0x7f, 0x76, 0x7a, 0x12, 0xf5, 0x4e, 0x70, 0xee, 0xcb, 0xc8, 0x68, 0x40, 0x11, 0x32, 0x3a, 0xe2, 0xfe, 0x2d, 0xd9, 0xf9, 0x07, 0x85, 0x57, 0x79, 0x69, 0xd7, 0xa2, 0x01, 0x3e, 0x8c, 0x12}, ValidationOpt: WarnOnly}, 2: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: [32]byte{0x42, 0x3e, 0x51, 0x3f, 0x60, 0x8d, 0x3e, 0x0e, 0x7b, 0xa4, 0xc4, 0xa4, 0x97, 0x50, 0xb4, 0x21, 0xed, 0x49, 0xde, 0xa6, 0x93, 0xb4, 0xdd, 0x60, 0xaa, 0x39, 0x0f, 0x12, 0x26, 0x34, 0x28, 0x38}, ValidationOpt: Enforce}, 6: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: [32]byte{0x12, 0x0e, 0x49, 0x8d, 0xb2, 0xa2, 0x24, 0xbd, 0x51, 0x2b, 0x6e, 0xfc, 0x9b, 0x02, 0x34, 0xf8, 0x43, 0xe1, 0x0b, 0xf0, 0x61, 0xeb, 0x7a, 0x76, 0xec, 0xca, 0x55, 0x09, 0xa2, 0x23, 0x89, 0x01}, ValidationOpt: WarnOnly}, 8: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: [32]byte{0xe1, 0x13, 0x34, 0x51, 0x4d, 0xf4, 0x9a, 0xf5, 0x6a, 0x2b, 0x13, 0x45, 0x3b, 0x3e, 0xbd, 0xc8, 0x96, 0xb0, 0xac, 0x1f, 0x36, 0x4c, 0x5c, 0x68, 0x34, 0xd4, 0x4a, 0x43, 0x6b, 0x80, 0x54, 0xe5}, ValidationOpt: Enforce}, 11: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: [32]byte{0x2a, 0xc0, 0xcd, 0x92, 0x5e, 0x18, 0x07, 0xfd, 0xe4, 0xf1, 0x48, 0x68, 0xa9, 0xdb, 0x58, 0x3e, 0x88, 0x24, 0x45, 0x50, 0x66, 0x5a, 0x2c, 0x5f, 0xc3, 0x7b, 0xac, 0xc5, 0x3d, 0x69, 0xb6, 0xa5}, ValidationOpt: Enforce}, 13: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: [32]byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
return M{0: {Expected: []byte{0x73, 0x7f, 0x76, 0x7a, 0x12, 0xf5, 0x4e, 0x70, 0xee, 0xcb, 0xc8, 0x68, 0x40, 0x11, 0x32, 0x3a, 0xe2, 0xfe, 0x2d, 0xd9, 0xf9, 0x07, 0x85, 0x57, 0x79, 0x69, 0xd7, 0xa2, 0x01, 0x3e, 0x8c, 0x12}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x42, 0x3e, 0x51, 0x3f, 0x60, 0x8d, 0x3e, 0x0e, 0x7b, 0xa4, 0xc4, 0xa4, 0x97, 0x50, 0xb4, 0x21, 0xed, 0x49, 0xde, 0xa6, 0x93, 0xb4, 0xdd, 0x60, 0xaa, 0x39, 0x0f, 0x12, 0x26, 0x34, 0x28, 0x38}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: []byte{0x12, 0x0e, 0x49, 0x8d, 0xb2, 0xa2, 0x24, 0xbd, 0x51, 0x2b, 0x6e, 0xfc, 0x9b, 0x02, 0x34, 0xf8, 0x43, 0xe1, 0x0b, 0xf0, 0x61, 0xeb, 0x7a, 0x76, 0xec, 0xca, 0x55, 0x09, 0xa2, 0x23, 0x89, 0x01}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xe1, 0x13, 0x34, 0x51, 0x4d, 0xf4, 0x9a, 0xf5, 0x6a, 0x2b, 0x13, 0x45, 0x3b, 0x3e, 0xbd, 0xc8, 0x96, 0xb0, 0xac, 0x1f, 0x36, 0x4c, 0x5c, 0x68, 0x34, 0xd4, 0x4a, 0x43, 0x6b, 0x80, 0x54, 0xe5}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x2a, 0xc0, 0xcd, 0x92, 0x5e, 0x18, 0x07, 0xfd, 0xe4, 0xf1, 0x48, 0x68, 0xa9, 0xdb, 0x58, 0x3e, 0x88, 0x24, 0x45, 0x50, 0x66, 0x5a, 0x2c, 0x5f, 0xc3, 0x7b, 0xac, 0xc5, 0x3d, 0x69, 0xb6, 0xa5}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
|
||||
case cloudprovider.Azure:
|
||||
return M{1: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: [32]byte{0x97, 0x29, 0x84, 0xaf, 0x96, 0xfa, 0xc7, 0x57, 0xfd, 0x3b, 0x5a, 0xb1, 0x88, 0x0c, 0xd2, 0x4d, 0x48, 0x23, 0x65, 0xe6, 0x32, 0x2c, 0x79, 0x22, 0x14, 0xb8, 0x20, 0x9d, 0xb6, 0x80, 0x15, 0x9a}, ValidationOpt: Enforce}, 7: {Expected: [32]byte{0x34, 0x65, 0x47, 0xa8, 0xce, 0x59, 0x57, 0xaf, 0x27, 0xe5, 0x52, 0x42, 0x7d, 0x6b, 0x9e, 0x6d, 0x9c, 0xb5, 0x02, 0xf0, 0x15, 0x6e, 0x91, 0x55, 0x38, 0x04, 0x51, 0xee, 0xa1, 0xb3, 0xf0, 0xed}, ValidationOpt: WarnOnly}, 8: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: [32]byte{0x64, 0x68, 0x17, 0x07, 0x27, 0x97, 0xdd, 0xc1, 0xd4, 0xf2, 0xcf, 0x76, 0x46, 0xfe, 0x59, 0xf1, 0x7c, 0x13, 0xc4, 0x1a, 0x7b, 0x59, 0x76, 0xd6, 0xa5, 0x40, 0xda, 0xe1, 0x1d, 0x71, 0x3d, 0x8c}, ValidationOpt: Enforce}, 11: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: [32]byte{0x36, 0xb5, 0xf8, 0x15, 0x3a, 0x8a, 0x31, 0x5b, 0xac, 0xd8, 0x75, 0x97, 0x8e, 0x92, 0x1e, 0xf7, 0xa1, 0xfc, 0x5c, 0x89, 0x25, 0x59, 0x03, 0x17, 0xbc, 0x1b, 0x53, 0xf2, 0x13, 0xb6, 0x75, 0x62}, ValidationOpt: Enforce}, 13: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: [32]byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
return M{1: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x97, 0x29, 0x84, 0xaf, 0x96, 0xfa, 0xc7, 0x57, 0xfd, 0x3b, 0x5a, 0xb1, 0x88, 0x0c, 0xd2, 0x4d, 0x48, 0x23, 0x65, 0xe6, 0x32, 0x2c, 0x79, 0x22, 0x14, 0xb8, 0x20, 0x9d, 0xb6, 0x80, 0x15, 0x9a}, ValidationOpt: Enforce}, 7: {Expected: []byte{0x34, 0x65, 0x47, 0xa8, 0xce, 0x59, 0x57, 0xaf, 0x27, 0xe5, 0x52, 0x42, 0x7d, 0x6b, 0x9e, 0x6d, 0x9c, 0xb5, 0x02, 0xf0, 0x15, 0x6e, 0x91, 0x55, 0x38, 0x04, 0x51, 0xee, 0xa1, 0xb3, 0xf0, 0xed}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x64, 0x68, 0x17, 0x07, 0x27, 0x97, 0xdd, 0xc1, 0xd4, 0xf2, 0xcf, 0x76, 0x46, 0xfe, 0x59, 0xf1, 0x7c, 0x13, 0xc4, 0x1a, 0x7b, 0x59, 0x76, 0xd6, 0xa5, 0x40, 0xda, 0xe1, 0x1d, 0x71, 0x3d, 0x8c}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x36, 0xb5, 0xf8, 0x15, 0x3a, 0x8a, 0x31, 0x5b, 0xac, 0xd8, 0x75, 0x97, 0x8e, 0x92, 0x1e, 0xf7, 0xa1, 0xfc, 0x5c, 0x89, 0x25, 0x59, 0x03, 0x17, 0xbc, 0x1b, 0x53, 0xf2, 0x13, 0xb6, 0x75, 0x62}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
|
||||
case cloudprovider.GCP:
|
||||
return M{1: {Expected: [32]byte{0x74, 0x5f, 0x2f, 0xb4, 0x23, 0x5e, 0x46, 0x47, 0xaa, 0x0a, 0xd5, 0xac, 0xe7, 0x81, 0xcd, 0x92, 0x9e, 0xb6, 0x8c, 0x28, 0x87, 0x0e, 0x7d, 0xd5, 0xd1, 0xa1, 0x53, 0x58, 0x54, 0x32, 0x5e, 0x56}, ValidationOpt: WarnOnly}, 2: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: [32]byte{0xb0, 0x9c, 0x1d, 0xff, 0x20, 0xbd, 0x38, 0x9e, 0xc9, 0xd0, 0x56, 0x53, 0x19, 0xa6, 0x55, 0x54, 0x08, 0x42, 0x6e, 0xe1, 0x72, 0x7b, 0x29, 0xbb, 0xb7, 0x16, 0xeb, 0xe9, 0x72, 0x9f, 0x81, 0xba}, ValidationOpt: Enforce}, 6: {Expected: [32]byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: [32]byte{0xb1, 0xe9, 0xb3, 0x05, 0x32, 0x5c, 0x51, 0xb9, 0x3d, 0xa5, 0x8c, 0xbf, 0x7f, 0x92, 0x51, 0x2d, 0x8e, 0xeb, 0xfa, 0x01, 0x14, 0x3e, 0x4d, 0x88, 0x44, 0xe4, 0x0e, 0x06, 0x2e, 0x9b, 0x6c, 0xd5}, ValidationOpt: WarnOnly}, 8: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: [32]byte{0x64, 0x68, 0x17, 0x07, 0x27, 0x97, 0xdd, 0xc1, 0xd4, 0xf2, 0xcf, 0x76, 0x46, 0xfe, 0x59, 0xf1, 0x7c, 0x13, 0xc4, 0x1a, 0x7b, 0x59, 0x76, 0xd6, 0xa5, 0x40, 0xda, 0xe1, 0x1d, 0x71, 0x3d, 0x8c}, ValidationOpt: Enforce}, 11: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: [32]byte{0xd7, 0x65, 0x82, 0xf1, 0x70, 0xcb, 0x84, 0x81, 0xc2, 0x55, 0x5c, 0x76, 0xae, 0x30, 0x39, 0xe9, 0xe1, 0x69, 0xfe, 0xcb, 0x05, 0x91, 0x2a, 0xa3, 0xb3, 0xcd, 0x7d, 0xc3, 0xec, 0xed, 0x0d, 0xa5}, ValidationOpt: Enforce}, 13: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: [32]byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
return M{1: {Expected: []byte{0x74, 0x5f, 0x2f, 0xb4, 0x23, 0x5e, 0x46, 0x47, 0xaa, 0x0a, 0xd5, 0xac, 0xe7, 0x81, 0xcd, 0x92, 0x9e, 0xb6, 0x8c, 0x28, 0x87, 0x0e, 0x7d, 0xd5, 0xd1, 0xa1, 0x53, 0x58, 0x54, 0x32, 0x5e, 0x56}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xb0, 0x9c, 0x1d, 0xff, 0x20, 0xbd, 0x38, 0x9e, 0xc9, 0xd0, 0x56, 0x53, 0x19, 0xa6, 0x55, 0x54, 0x08, 0x42, 0x6e, 0xe1, 0x72, 0x7b, 0x29, 0xbb, 0xb7, 0x16, 0xeb, 0xe9, 0x72, 0x9f, 0x81, 0xba}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: []byte{0xb1, 0xe9, 0xb3, 0x05, 0x32, 0x5c, 0x51, 0xb9, 0x3d, 0xa5, 0x8c, 0xbf, 0x7f, 0x92, 0x51, 0x2d, 0x8e, 0xeb, 0xfa, 0x01, 0x14, 0x3e, 0x4d, 0x88, 0x44, 0xe4, 0x0e, 0x06, 0x2e, 0x9b, 0x6c, 0xd5}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x64, 0x68, 0x17, 0x07, 0x27, 0x97, 0xdd, 0xc1, 0xd4, 0xf2, 0xcf, 0x76, 0x46, 0xfe, 0x59, 0xf1, 0x7c, 0x13, 0xc4, 0x1a, 0x7b, 0x59, 0x76, 0xd6, 0xa5, 0x40, 0xda, 0xe1, 0x1d, 0x71, 0x3d, 0x8c}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0xd7, 0x65, 0x82, 0xf1, 0x70, 0xcb, 0x84, 0x81, 0xc2, 0x55, 0x5c, 0x76, 0xae, 0x30, 0x39, 0xe9, 0xe1, 0x69, 0xfe, 0xcb, 0x05, 0x91, 0x2a, 0xa3, 0xb3, 0xcd, 0x7d, 0xc3, 0xec, 0xed, 0x0d, 0xa5}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
|
||||
case cloudprovider.QEMU:
|
||||
return M{4: {Expected: [32]byte{0xbd, 0x7c, 0x7a, 0x6f, 0x43, 0xd9, 0xa7, 0x16, 0x4a, 0xf5, 0x17, 0xb1, 0xe5, 0x43, 0x2c, 0x14, 0x31, 0xe2, 0xd5, 0xd1, 0x01, 0xe9, 0x5e, 0x7f, 0x52, 0x73, 0x76, 0xda, 0xc2, 0x0b, 0xe8, 0x70}, ValidationOpt: Enforce}, 8: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: [32]byte{0xe1, 0x13, 0x34, 0x51, 0x4d, 0xf4, 0x9a, 0xf5, 0x6a, 0x2b, 0x13, 0x45, 0x3b, 0x3e, 0xbd, 0xc8, 0x96, 0xb0, 0xac, 0x1f, 0x36, 0x4c, 0x5c, 0x68, 0x34, 0xd4, 0x4a, 0x43, 0x6b, 0x80, 0x54, 0xe5}, ValidationOpt: Enforce}, 11: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: [32]byte{0x2c, 0x45, 0x39, 0xc4, 0x40, 0x95, 0xa3, 0x2a, 0x4e, 0xb2, 0xde, 0x12, 0xb2, 0x04, 0x2a, 0x34, 0xaa, 0x13, 0xaf, 0x5f, 0x30, 0x79, 0xef, 0x95, 0x2a, 0x0f, 0xca, 0xaa, 0x07, 0x6a, 0x27, 0x2d}, ValidationOpt: Enforce}, 13: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 15: {Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
return M{4: {Expected: []byte{0xbd, 0x7c, 0x7a, 0x6f, 0x43, 0xd9, 0xa7, 0x16, 0x4a, 0xf5, 0x17, 0xb1, 0xe5, 0x43, 0x2c, 0x14, 0x31, 0xe2, 0xd5, 0xd1, 0x01, 0xe9, 0x5e, 0x7f, 0x52, 0x73, 0x76, 0xda, 0xc2, 0x0b, 0xe8, 0x70}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xe1, 0x13, 0x34, 0x51, 0x4d, 0xf4, 0x9a, 0xf5, 0x6a, 0x2b, 0x13, 0x45, 0x3b, 0x3e, 0xbd, 0xc8, 0x96, 0xb0, 0xac, 0x1f, 0x36, 0x4c, 0x5c, 0x68, 0x34, 0xd4, 0x4a, 0x43, 0x6b, 0x80, 0x54, 0xe5}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x2c, 0x45, 0x39, 0xc4, 0x40, 0x95, 0xa3, 0x2a, 0x4e, 0xb2, 0xde, 0x12, 0xb2, 0x04, 0x2a, 0x34, 0xaa, 0x13, 0xaf, 0x5f, 0x30, 0x79, 0xef, 0x95, 0x2a, 0x0f, 0xca, 0xaa, 0x07, 0x6a, 0x27, 0x2d}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
|
||||
default:
|
||||
return nil
|
||||
|
@ -9,6 +9,7 @@ package measurements
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -30,14 +31,14 @@ func TestMarshal(t *testing.T) {
|
||||
}{
|
||||
"measurement": {
|
||||
m: Measurement{
|
||||
Expected: [32]byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
Expected: []byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
},
|
||||
wantYAML: "expected: \"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35\"\nwarnOnly: false",
|
||||
wantJSON: `{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35","warnOnly":false}`,
|
||||
},
|
||||
"warn only": {
|
||||
m: Measurement{
|
||||
Expected: [32]byte{1, 2, 3, 4}, // implicitly padded with 0s
|
||||
Expected: []byte{1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
ValidationOpt: WarnOnly,
|
||||
},
|
||||
wantYAML: "expected: \"0102030400000000000000000000000000000000000000000000000000000000\"\nwarnOnly: true",
|
||||
@ -81,10 +82,10 @@ func TestUnmarshal(t *testing.T) {
|
||||
inputJSON: `{"2":{"expected":"/V3p3zUOO8RBCsBrv+XM3rk/U7nvUSOfdSzmnbxgDzU="},"3":{"expected":"1aRJbSHeyaUljdsZxv61O7TTwEY/5gfySI3fTxAG754="}}`,
|
||||
wantMeasurements: M{
|
||||
2: {
|
||||
Expected: [32]byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
Expected: []byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
},
|
||||
3: {
|
||||
Expected: [32]byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158},
|
||||
Expected: []byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -93,10 +94,22 @@ func TestUnmarshal(t *testing.T) {
|
||||
inputJSON: `{"2":{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35"},"3":{"expected":"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463fe607f2488ddf4f1006ef9e"}}`,
|
||||
wantMeasurements: M{
|
||||
2: {
|
||||
Expected: [32]byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
Expected: []byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
},
|
||||
3: {
|
||||
Expected: [32]byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158},
|
||||
Expected: []byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158},
|
||||
},
|
||||
},
|
||||
},
|
||||
"valid measurements hex 48 bytes": {
|
||||
inputYAML: "2:\n expected: \"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35fd5de9df350e3bc4410ac06bbfe5ccde\"\n3:\n expected: \"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463fe607f2488ddf4f1006ef9efd5de9df350e3bc4410ac06bbfe5ccde\"",
|
||||
inputJSON: `{"2":{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35fd5de9df350e3bc4410ac06bbfe5ccde"},"3":{"expected":"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463fe607f2488ddf4f1006ef9efd5de9df350e3bc4410ac06bbfe5ccde"}}`,
|
||||
wantMeasurements: M{
|
||||
2: {
|
||||
Expected: []byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53, 253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222},
|
||||
},
|
||||
3: {
|
||||
Expected: []byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158, 253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -105,10 +118,10 @@ func TestUnmarshal(t *testing.T) {
|
||||
inputJSON: `{"2":{"expected":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},"3":{"expected":"AQIDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}}`,
|
||||
wantMeasurements: M{
|
||||
2: {
|
||||
Expected: [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Expected: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
3: {
|
||||
Expected: [32]byte{1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Expected: []byte{1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -122,10 +135,10 @@ func TestUnmarshal(t *testing.T) {
|
||||
inputJSON: `{"2":"/V3p3zUOO8RBCsBrv+XM3rk/U7nvUSOfdSzmnbxgDzU=","3":"1aRJbSHeyaUljdsZxv61O7TTwEY/5gfySI3fTxAG754="}`,
|
||||
wantMeasurements: M{
|
||||
2: {
|
||||
Expected: [32]byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
Expected: []byte{253, 93, 233, 223, 53, 14, 59, 196, 65, 10, 192, 107, 191, 229, 204, 222, 185, 63, 83, 185, 239, 81, 35, 159, 117, 44, 230, 157, 188, 96, 15, 53},
|
||||
},
|
||||
3: {
|
||||
Expected: [32]byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158},
|
||||
Expected: []byte{213, 164, 73, 109, 33, 222, 201, 165, 37, 141, 219, 25, 198, 254, 181, 59, 180, 211, 192, 70, 63, 230, 7, 242, 72, 141, 223, 79, 16, 6, 239, 158},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -134,6 +147,11 @@ func TestUnmarshal(t *testing.T) {
|
||||
inputJSON: `{"2":{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef"},"3":{"expected":"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463f"}}`,
|
||||
wantErr: true,
|
||||
},
|
||||
"mixed length hex": {
|
||||
inputYAML: "2:\n expected: \"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35fd5de9df350e3bc4410ac06bbfe5ccde\"\n3:\n expected: \"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463fe607f2488ddf4f1006ef9e\"",
|
||||
inputJSON: `{"2":{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35fd5de9df350e3bc4410ac06bbfe5ccde"},"3":{"expected":"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463fe607f2488ddf4f1006ef9e"}}`,
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid length base64": {
|
||||
inputYAML: "2:\n expected: \"AA==\"\n3:\n expected: \"AQIDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\"",
|
||||
inputJSON: `{"2":{"expected":"AA=="},"3":{"expected":"AQIDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="}}`,
|
||||
@ -170,6 +188,7 @@ func TestUnmarshal(t *testing.T) {
|
||||
err := json.Unmarshal([]byte(tc.inputJSON), &m)
|
||||
|
||||
if tc.wantErr {
|
||||
fmt.Println(err)
|
||||
assert.Error(err, "json.Unmarshal should have failed")
|
||||
} else {
|
||||
require.NoError(err, "json.Unmarshal failed")
|
||||
@ -200,10 +219,10 @@ func TestEncodeM(t *testing.T) {
|
||||
},
|
||||
"output is sorted": {
|
||||
m: M{
|
||||
3: {},
|
||||
1: {},
|
||||
11: {},
|
||||
2: {},
|
||||
3: WithAllBytes(0, false),
|
||||
1: WithAllBytes(0, false),
|
||||
11: WithAllBytes(0, false),
|
||||
2: WithAllBytes(0, false),
|
||||
},
|
||||
want: `1:
|
||||
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
@ -605,7 +624,7 @@ func TestWithAllBytes(t *testing.T) {
|
||||
b: 0x00,
|
||||
warnOnly: true,
|
||||
wantMeasurement: Measurement{
|
||||
Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
ValidationOpt: WarnOnly,
|
||||
},
|
||||
},
|
||||
@ -613,7 +632,7 @@ func TestWithAllBytes(t *testing.T) {
|
||||
b: 0x00,
|
||||
warnOnly: false,
|
||||
wantMeasurement: Measurement{
|
||||
Expected: [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
ValidationOpt: Enforce,
|
||||
},
|
||||
},
|
||||
@ -621,7 +640,7 @@ func TestWithAllBytes(t *testing.T) {
|
||||
b: 0x01,
|
||||
warnOnly: true,
|
||||
wantMeasurement: Measurement{
|
||||
Expected: [32]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
Expected: []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
ValidationOpt: WarnOnly,
|
||||
},
|
||||
},
|
||||
@ -629,7 +648,7 @@ func TestWithAllBytes(t *testing.T) {
|
||||
b: 0x01,
|
||||
warnOnly: false,
|
||||
wantMeasurement: Measurement{
|
||||
Expected: [32]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
Expected: []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
ValidationOpt: Enforce,
|
||||
},
|
||||
},
|
||||
@ -637,7 +656,7 @@ func TestWithAllBytes(t *testing.T) {
|
||||
b: 0xFF,
|
||||
warnOnly: true,
|
||||
wantMeasurement: Measurement{
|
||||
Expected: [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
Expected: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
ValidationOpt: WarnOnly,
|
||||
},
|
||||
},
|
||||
@ -645,7 +664,7 @@ func TestWithAllBytes(t *testing.T) {
|
||||
b: 0xFF,
|
||||
warnOnly: false,
|
||||
wantMeasurement: Measurement{
|
||||
Expected: [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
Expected: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
ValidationOpt: Enforce,
|
||||
},
|
||||
},
|
||||
|
@ -10,6 +10,7 @@ go_library(
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/qemu",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
@ -22,7 +23,7 @@ type Issuer struct {
|
||||
}
|
||||
|
||||
// NewIssuer initializes a new QEMU Issuer.
|
||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
return &Issuer{
|
||||
Issuer: vtpm.NewIssuer(
|
||||
vtpm.OpenVTPM,
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"crypto"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
@ -24,7 +25,7 @@ type Validator struct {
|
||||
}
|
||||
|
||||
// NewValidator initializes a new QEMU validator with the provided PCR values.
|
||||
func NewValidator(cfg *config.QEMUVTPM, log vtpm.AttestationLogger) *Validator {
|
||||
func NewValidator(cfg *config.QEMUVTPM, log attestation.Logger) *Validator {
|
||||
return &Validator{
|
||||
Validator: vtpm.NewValidator(
|
||||
cfg.Measurements,
|
||||
|
21
internal/attestation/tdx/BUILD.bazel
Normal file
21
internal/attestation/tdx/BUILD.bazel
Normal file
@ -0,0 +1,21 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "tdx",
|
||||
srcs = [
|
||||
"issuer.go",
|
||||
"tdx.go",
|
||||
"validator.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/tdx",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//tdx",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//verification",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//verification/types",
|
||||
],
|
||||
)
|
67
internal/attestation/tdx/issuer.go
Normal file
67
internal/attestation/tdx/issuer.go
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package tdx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/go-tdx-qpl/tdx"
|
||||
)
|
||||
|
||||
// Issuer is the TDX attestation issuer.
|
||||
type Issuer struct {
|
||||
variant.QEMUTDX
|
||||
|
||||
open OpenFunc
|
||||
log attestation.Logger
|
||||
}
|
||||
|
||||
// NewIssuer initializes a new TDX Issuer.
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
if log == nil {
|
||||
log = attestation.NOPLogger{}
|
||||
}
|
||||
return &Issuer{
|
||||
open: Open,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// Issue issues a TDX attestation document.
|
||||
func (i *Issuer) Issue(_ context.Context, userData []byte, nonce []byte) (attDoc []byte, err error) {
|
||||
i.log.Infof("Issuing attestation statement")
|
||||
defer func() {
|
||||
if err != nil {
|
||||
i.log.Warnf("Failed to issue attestation document: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
handle, err := i.open()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening TDX device: %w", err)
|
||||
}
|
||||
defer handle.Close()
|
||||
|
||||
quote, err := tdx.GenerateQuote(handle, attestation.MakeExtraData(userData, nonce))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generating quote: %w", err)
|
||||
}
|
||||
|
||||
rawAttDoc, err := json.Marshal(tdxAttestationDocument{
|
||||
RawQuote: quote,
|
||||
UserData: userData,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshaling attestation document: %w", err)
|
||||
}
|
||||
|
||||
return rawAttDoc, nil
|
||||
}
|
95
internal/attestation/tdx/tdx.go
Normal file
95
internal/attestation/tdx/tdx.go
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
// Package TDX implements attestation for Intel TDX.
|
||||
package tdx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/go-tdx-qpl/tdx"
|
||||
)
|
||||
|
||||
type tdxAttestationDocument struct {
|
||||
// RawQuote is the raw TDX quote.
|
||||
RawQuote []byte
|
||||
// UserData is the user data that was passed to the enclave and was included in the quote.
|
||||
UserData []byte
|
||||
}
|
||||
|
||||
// Device is an interface for a TDX device.
|
||||
type Device interface {
|
||||
io.ReadWriteCloser
|
||||
Fd() uintptr
|
||||
}
|
||||
|
||||
// OpenFunc is a function that opens the TDX device.
|
||||
type OpenFunc func() (Device, error)
|
||||
|
||||
// GetSelectedMeasurements returns the selected measurements from the RTMRs.
|
||||
func GetSelectedMeasurements(open OpenFunc, selection []int) (measurements.M, error) {
|
||||
for _, idx := range selection {
|
||||
if idx < 0 || idx >= 5 {
|
||||
return nil, fmt.Errorf("invalid measurement index %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
handle, err := open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer handle.Close()
|
||||
|
||||
tdxMeasurements, err := tdx.ReadMeasurements(handle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := make(measurements.M)
|
||||
for _, idx := range selection {
|
||||
m[uint32(idx)] = measurements.Measurement{
|
||||
Expected: tdxMeasurements[idx][:],
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Available returns true if the TDX device is available and can be opened.
|
||||
func Available() bool {
|
||||
handle, err := Open()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer handle.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
// Open opens the TDX guest device.
|
||||
func Open() (Device, error) {
|
||||
handle, err := os.Open(tdx.GuestDevice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// IsTDXDevice checks if the given device is a TDX guest device.
|
||||
func IsTDXDevice(device io.ReadWriteCloser) (Device, bool) {
|
||||
handle, ok := device.(Device)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
f, ok := device.(*os.File)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return handle, f.Name() == tdx.GuestDevice
|
||||
}
|
94
internal/attestation/tdx/validator.go
Normal file
94
internal/attestation/tdx/validator.go
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package tdx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/go-tdx-qpl/verification"
|
||||
"github.com/edgelesssys/go-tdx-qpl/verification/types"
|
||||
)
|
||||
|
||||
type tdxVerifier interface {
|
||||
Verify(ctx context.Context, quote []byte) (types.SGXQuote4, error)
|
||||
}
|
||||
|
||||
// Validator is the TDX attestation validator.
|
||||
type Validator struct {
|
||||
variant.QEMUTDX
|
||||
|
||||
tdx tdxVerifier
|
||||
expected measurements.M
|
||||
|
||||
log attestation.Logger
|
||||
}
|
||||
|
||||
// NewValidator initializes a new TDX Validator.
|
||||
func NewValidator(cfg *config.QEMUTDX, log attestation.Logger) *Validator {
|
||||
if log == nil {
|
||||
log = attestation.NOPLogger{}
|
||||
}
|
||||
|
||||
return &Validator{
|
||||
tdx: verification.New(),
|
||||
expected: cfg.Measurements,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the given attestation document using TDX attestation.
|
||||
func (v *Validator) Validate(ctx context.Context, attDocRaw []byte, nonce []byte) (userData []byte, err error) {
|
||||
v.log.Infof("Validating attestation document")
|
||||
defer func() {
|
||||
if err != nil {
|
||||
v.log.Warnf("Failed to validate attestation document: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var attDoc tdxAttestationDocument
|
||||
if err := json.Unmarshal(attDocRaw, &attDoc); err != nil {
|
||||
return nil, fmt.Errorf("unmarshaling attestation document: %w", err)
|
||||
}
|
||||
|
||||
// Verify the quote.
|
||||
quote, err := v.tdx.Verify(ctx, attDoc.RawQuote)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("verifying TDX quote: %w", err)
|
||||
}
|
||||
|
||||
// Report data
|
||||
extraData := attestation.MakeExtraData(attDoc.UserData, nonce)
|
||||
if !attestation.CompareExtraData(quote.Body.ReportData[:], extraData) {
|
||||
return nil, fmt.Errorf("report data in TDX quote does not match provided nonce")
|
||||
}
|
||||
|
||||
// Convert RTMRs and MRTD to map.
|
||||
tdMeasure := make(map[uint32][]byte, 5)
|
||||
tdMeasure[0] = quote.Body.MRTD[:]
|
||||
for idx := 0; idx < len(quote.Body.RTMR); idx++ {
|
||||
tdMeasure[uint32(idx+1)] = quote.Body.RTMR[idx][:]
|
||||
}
|
||||
|
||||
// Verify the quote against the expected measurements.
|
||||
for idx, ex := range v.expected {
|
||||
if !bytes.Equal(ex.Expected, tdMeasure[idx]) {
|
||||
if !ex.ValidationOpt {
|
||||
return nil, fmt.Errorf("untrusted TD measurement value at index %d", idx)
|
||||
}
|
||||
v.log.Warnf("Encountered untrusted TD measurement value at index %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
return attDoc.UserData, nil
|
||||
}
|
@ -5,12 +5,12 @@ go_library(
|
||||
name = "vtpm",
|
||||
srcs = [
|
||||
"attestation.go",
|
||||
"initialize.go",
|
||||
"vtpm.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/vtpm",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/measurements",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
@ -24,7 +24,6 @@ go_test(
|
||||
name = "vtpm_test",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"initialize_test.go",
|
||||
"vtpm_test.go",
|
||||
],
|
||||
embed = [":vtpm"],
|
||||
@ -34,6 +33,7 @@ go_test(
|
||||
"//conditions:default": ["disable_tpm_simulator"],
|
||||
}),
|
||||
deps = [
|
||||
"//internal/attestation/initialize",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/simulator",
|
||||
"//internal/logger",
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -21,6 +20,7 @@ import (
|
||||
tpmServer "github.com/google/go-tpm-tools/server"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
)
|
||||
|
||||
@ -66,12 +66,6 @@ type (
|
||||
ValidateCVM func(attestation AttestationDocument, state *attest.MachineState) error
|
||||
)
|
||||
|
||||
// AttestationLogger is a logger used to print warnings and infos during attestation validation.
|
||||
type AttestationLogger interface {
|
||||
Infof(format string, args ...any)
|
||||
Warnf(format string, args ...any)
|
||||
}
|
||||
|
||||
// AttestationDocument contains the TPM attestation with signed user data.
|
||||
type AttestationDocument struct {
|
||||
// Attestation contains the TPM event log, PCR values and quotes, and public key of the key used to sign the attestation.
|
||||
@ -87,16 +81,16 @@ type Issuer struct {
|
||||
openTPM TPMOpenFunc
|
||||
getAttestationKey GetTPMAttestationKey
|
||||
getInstanceInfo GetInstanceInfo
|
||||
log AttestationLogger
|
||||
log attestation.Logger
|
||||
}
|
||||
|
||||
// NewIssuer returns a new Issuer.
|
||||
func NewIssuer(
|
||||
openTPM TPMOpenFunc, getAttestationKey GetTPMAttestationKey,
|
||||
getInstanceInfo GetInstanceInfo, log AttestationLogger,
|
||||
getInstanceInfo GetInstanceInfo, log attestation.Logger,
|
||||
) *Issuer {
|
||||
if log == nil {
|
||||
log = &nopAttestationLogger{}
|
||||
log = &attestation.NOPLogger{}
|
||||
}
|
||||
return &Issuer{
|
||||
openTPM: openTPM,
|
||||
@ -129,7 +123,7 @@ func (i *Issuer) Issue(ctx context.Context, userData []byte, nonce []byte) (res
|
||||
defer aK.Close()
|
||||
|
||||
// Create an attestation using the loaded key
|
||||
extraData := makeExtraData(userData, nonce)
|
||||
extraData := attestation.MakeExtraData(userData, nonce)
|
||||
tpmAttestation, err := aK.Attest(tpmClient.AttestOpts{Nonce: extraData})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating attestation: %w", err)
|
||||
@ -162,15 +156,15 @@ type Validator struct {
|
||||
getTrustedKey GetTPMTrustedAttestationPublicKey
|
||||
validateCVM ValidateCVM
|
||||
|
||||
log AttestationLogger
|
||||
log attestation.Logger
|
||||
}
|
||||
|
||||
// NewValidator returns a new Validator.
|
||||
func NewValidator(expected measurements.M, getTrustedKey GetTPMTrustedAttestationPublicKey,
|
||||
validateCVM ValidateCVM, log AttestationLogger,
|
||||
validateCVM ValidateCVM, log attestation.Logger,
|
||||
) *Validator {
|
||||
if log == nil {
|
||||
log = &nopAttestationLogger{}
|
||||
log = &attestation.NOPLogger{}
|
||||
}
|
||||
return &Validator{
|
||||
expected: expected,
|
||||
@ -194,7 +188,7 @@ func (v *Validator) Validate(ctx context.Context, attDocRaw []byte, nonce []byte
|
||||
return nil, fmt.Errorf("unmarshaling TPM attestation document: %w", err)
|
||||
}
|
||||
|
||||
extraData := makeExtraData(attDoc.UserData, nonce)
|
||||
extraData := attestation.MakeExtraData(attDoc.UserData, nonce)
|
||||
|
||||
// Verify and retrieve the trusted attestation public key using the provided instance info
|
||||
aKP, err := v.getTrustedKey(ctx, attDoc, extraData)
|
||||
@ -276,25 +270,9 @@ func GetSelectedMeasurements(open TPMOpenFunc, selection tpm2.PCRSelection) (mea
|
||||
return nil, fmt.Errorf("invalid measurement: invalid length: %d", len(pcr))
|
||||
}
|
||||
m[i] = measurements.Measurement{
|
||||
Expected: *(*[32]byte)(pcr),
|
||||
Expected: pcr,
|
||||
}
|
||||
}
|
||||
|
||||
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{}
|
||||
|
||||
// Infof is a no-op.
|
||||
func (nopAttestationLogger) Infof(string, ...interface{}) {}
|
||||
|
||||
// Warnf is a no-op.
|
||||
func (nopAttestationLogger) Warnf(string, ...interface{}) {}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||
tpmsim "github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||
@ -100,7 +101,7 @@ func TestValidate(t *testing.T) {
|
||||
require.Equal(challenge, out)
|
||||
|
||||
// validation must fail after bootstrapping (change of enforced PCR)
|
||||
require.NoError(MarkNodeAsBootstrapped(tpmOpen, []byte{2}))
|
||||
require.NoError(initialize.MarkNodeAsBootstrapped(tpmOpen, []byte{2}))
|
||||
attDocBootstrappedRaw, err := issuer.Issue(ctx, challenge, nonce)
|
||||
require.NoError(err)
|
||||
_, err = validator.Validate(ctx, attDocBootstrappedRaw, nonce)
|
||||
@ -121,19 +122,19 @@ func TestValidate(t *testing.T) {
|
||||
0: measurements.WithAllBytes(0x00, measurements.WarnOnly),
|
||||
1: measurements.WithAllBytes(0x00, measurements.WarnOnly),
|
||||
2: measurements.Measurement{
|
||||
Expected: [32]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20},
|
||||
Expected: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20},
|
||||
ValidationOpt: measurements.WarnOnly,
|
||||
},
|
||||
3: measurements.Measurement{
|
||||
Expected: [32]byte{0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40},
|
||||
Expected: []byte{0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40},
|
||||
ValidationOpt: measurements.WarnOnly,
|
||||
},
|
||||
4: measurements.Measurement{
|
||||
Expected: [32]byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60},
|
||||
Expected: []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60},
|
||||
ValidationOpt: measurements.WarnOnly,
|
||||
},
|
||||
5: measurements.Measurement{
|
||||
Expected: [32]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80},
|
||||
Expected: []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80},
|
||||
ValidationOpt: measurements.WarnOnly,
|
||||
},
|
||||
}
|
||||
@ -202,7 +203,7 @@ func TestValidate(t *testing.T) {
|
||||
validator: NewValidator(
|
||||
measurements.M{
|
||||
0: measurements.Measurement{
|
||||
Expected: [32]byte{0xFF},
|
||||
Expected: []byte{0xFF},
|
||||
ValidationOpt: measurements.Enforce,
|
||||
},
|
||||
},
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package vtpm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// MarkNodeAsBootstrapped marks a node as initialized by extending PCRs.
|
||||
func MarkNodeAsBootstrapped(openTPM TPMOpenFunc, clusterID []byte) error {
|
||||
tpm, err := openTPM()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tpm.Close()
|
||||
|
||||
// clusterID is used to uniquely identify this running instance of Constellation
|
||||
return tpm2.PCREvent(tpm, measurements.PCRIndexClusterID, clusterID)
|
||||
}
|
||||
|
||||
// IsNodeBootstrapped checks if a node is already bootstrapped by reading PCRs.
|
||||
func IsNodeBootstrapped(openTPM TPMOpenFunc) (bool, error) {
|
||||
tpm, err := openTPM()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer tpm.Close()
|
||||
|
||||
idxClusterID := int(measurements.PCRIndexClusterID)
|
||||
pcrs, err := tpm2.ReadPCRs(tpm, tpm2.PCRSelection{
|
||||
Hash: tpm2.AlgSHA256,
|
||||
PCRs: []int{idxClusterID},
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(pcrs[idxClusterID]) == 0 {
|
||||
return false, errors.New("cluster ID PCR does not exist")
|
||||
}
|
||||
return pcrInitialized(pcrs[idxClusterID]), nil
|
||||
|
||||
/* Old code that will be reenabled in the future
|
||||
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
|
||||
}
|
@ -9,16 +9,9 @@ package vtpm
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/goleak"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
goleak.VerifyTestMain(m)
|
||||
}
|
||||
|
||||
func TestNOPTPM(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
assert.NoError(MarkNodeAsBootstrapped(OpenNOPTPM, []byte{0x0, 0x1, 0x2, 0x3}))
|
||||
}
|
||||
|
@ -885,6 +885,37 @@ func (c QEMUVTPM) EqualTo(other AttestationCfg) (bool, error) {
|
||||
return c.Measurements.EqualTo(otherCfg.Measurements), nil
|
||||
}
|
||||
|
||||
// QEMUTDX is the configuration for QEMU TDX attestation.
|
||||
type QEMUTDX struct {
|
||||
// description: |
|
||||
// Expected TDX measurements.
|
||||
Measurements measurements.M `json:"measurements" yaml:"measurements" validate:"required,no_placeholders"`
|
||||
}
|
||||
|
||||
// GetVariant returns qemu-tdx as the variant.
|
||||
func (QEMUTDX) GetVariant() variant.Variant {
|
||||
return variant.QEMUTDX{}
|
||||
}
|
||||
|
||||
// GetMeasurements returns the measurements used for attestation.
|
||||
func (c QEMUTDX) GetMeasurements() measurements.M {
|
||||
return c.Measurements
|
||||
}
|
||||
|
||||
// SetMeasurements updates a config's measurements using the given measurements.
|
||||
func (c *QEMUTDX) SetMeasurements(m measurements.M) {
|
||||
c.Measurements = m
|
||||
}
|
||||
|
||||
// EqualTo returns true if the config is equal to the given config.
|
||||
func (c QEMUTDX) EqualTo(other AttestationCfg) (bool, error) {
|
||||
otherCfg, ok := other.(*QEMUTDX)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("cannot compare %T with %T", c, other)
|
||||
}
|
||||
return c.Measurements.EqualTo(otherCfg.Measurements), nil
|
||||
}
|
||||
|
||||
func toPtr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ const (
|
||||
azureSEVSNP = "azure-sev-snp"
|
||||
azureTrustedLaunch = "azure-trustedlaunch"
|
||||
qemuVTPM = "qemu-vtpm"
|
||||
qemuTDX = "qemu-tdx"
|
||||
)
|
||||
|
||||
// Getter returns an ASN.1 Object Identifier.
|
||||
@ -72,6 +73,8 @@ func FromString(oid string) (Variant, error) {
|
||||
return AzureTrustedLaunch{}, nil
|
||||
case qemuVTPM:
|
||||
return QEMUVTPM{}, nil
|
||||
case qemuTDX:
|
||||
return QEMUTDX{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown OID: %q", oid)
|
||||
}
|
||||
@ -183,3 +186,22 @@ func (QEMUVTPM) String() string {
|
||||
func (QEMUVTPM) Equal(other Getter) bool {
|
||||
return other.OID().Equal(QEMUVTPM{}.OID())
|
||||
}
|
||||
|
||||
// QEMUTDX holds the QEMU TDX OID.
|
||||
// Placeholder for dev-cloud integration.
|
||||
type QEMUTDX struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
// Placeholder for dev-cloud integration.
|
||||
func (QEMUTDX) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 5, 99}
|
||||
}
|
||||
|
||||
func (QEMUTDX) String() string {
|
||||
return qemuTDX
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also QEMUTDX.
|
||||
func (QEMUTDX) Equal(other Getter) bool {
|
||||
return other.OID().Equal(QEMUTDX{}.OID())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user