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=",
|
sum = "h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=",
|
||||||
version = "v0.0.0-20230303085714-62ede861d33f",
|
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(
|
go_repository(
|
||||||
name = "com_github_edsrzf_mmap_go",
|
name = "com_github_edsrzf_mmap_go",
|
||||||
@ -6680,6 +6688,15 @@ def go_dependencies():
|
|||||||
sum = "h1:gpw/0Ku+6RgF3jsi7fnCLmlcikBHfKBCUcu1qgc16OU=",
|
sum = "h1:gpw/0Ku+6RgF3jsi7fnCLmlcikBHfKBCUcu1qgc16OU=",
|
||||||
version = "v0.20.3",
|
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(
|
go_repository(
|
||||||
name = "com_github_weppos_publicsuffix_go",
|
name = "com_github_weppos_publicsuffix_go",
|
||||||
build_file_generation = "on",
|
build_file_generation = "on",
|
||||||
|
@ -23,7 +23,9 @@ go_library(
|
|||||||
"//bootstrapper/internal/nodelock",
|
"//bootstrapper/internal/nodelock",
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation/choose",
|
"//internal/attestation/choose",
|
||||||
|
"//internal/attestation/initialize",
|
||||||
"//internal/attestation/simulator",
|
"//internal/attestation/simulator",
|
||||||
|
"//internal/attestation/tdx",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/cloud/aws",
|
"//internal/cloud/aws",
|
||||||
"//internal/cloud/azure",
|
"//internal/cloud/azure",
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/tdx"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
awscloud "github.com/edgelesssys/constellation/v2/internal/cloud/aws"
|
awscloud "github.com/edgelesssys/constellation/v2/internal/cloud/aws"
|
||||||
azurecloud "github.com/edgelesssys/constellation/v2/internal/cloud/azure"
|
azurecloud "github.com/edgelesssys/constellation/v2/internal/cloud/azure"
|
||||||
@ -63,7 +64,7 @@ func main() {
|
|||||||
var clusterInitJoiner clusterInitJoiner
|
var clusterInitJoiner clusterInitJoiner
|
||||||
var metadataAPI metadataAPI
|
var metadataAPI metadataAPI
|
||||||
var cloudLogger logging.CloudLogger
|
var cloudLogger logging.CloudLogger
|
||||||
var openTPM vtpm.TPMOpenFunc
|
var openDevice vtpm.TPMOpenFunc
|
||||||
var fs afero.Fs
|
var fs afero.Fs
|
||||||
|
|
||||||
helmClient, err := helm.New(log)
|
helmClient, err := helm.New(log)
|
||||||
@ -97,7 +98,7 @@ func main() {
|
|||||||
"aws", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.New(),
|
"aws", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.New(),
|
||||||
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
||||||
)
|
)
|
||||||
openTPM = vtpm.OpenVTPM
|
openDevice = vtpm.OpenVTPM
|
||||||
fs = afero.NewOsFs()
|
fs = afero.NewOsFs()
|
||||||
|
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.GCP:
|
||||||
@ -117,7 +118,7 @@ func main() {
|
|||||||
"gcp", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.New(),
|
"gcp", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.New(),
|
||||||
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
||||||
)
|
)
|
||||||
openTPM = vtpm.OpenVTPM
|
openDevice = vtpm.OpenVTPM
|
||||||
fs = afero.NewOsFs()
|
fs = afero.NewOsFs()
|
||||||
log.Infof("Added load balancer IP to routing table")
|
log.Infof("Added load balancer IP to routing table")
|
||||||
|
|
||||||
@ -136,7 +137,7 @@ func main() {
|
|||||||
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
metadata, helmClient, &kubewaiter.CloudKubeAPIWaiter{},
|
||||||
)
|
)
|
||||||
|
|
||||||
openTPM = vtpm.OpenVTPM
|
openDevice = vtpm.OpenVTPM
|
||||||
fs = afero.NewOsFs()
|
fs = afero.NewOsFs()
|
||||||
|
|
||||||
case cloudprovider.QEMU:
|
case cloudprovider.QEMU:
|
||||||
@ -148,7 +149,16 @@ func main() {
|
|||||||
)
|
)
|
||||||
metadataAPI = metadata
|
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()
|
fs = afero.NewOsFs()
|
||||||
case cloudprovider.OpenStack:
|
case cloudprovider.OpenStack:
|
||||||
cloudLogger = &logging.NopLogger{}
|
cloudLogger = &logging.NopLogger{}
|
||||||
@ -162,19 +172,18 @@ func main() {
|
|||||||
)
|
)
|
||||||
metadataAPI = metadata
|
metadataAPI = metadata
|
||||||
|
|
||||||
openTPM = vtpm.OpenVTPM
|
|
||||||
fs = afero.NewOsFs()
|
fs = afero.NewOsFs()
|
||||||
default:
|
default:
|
||||||
clusterInitJoiner = &clusterFake{}
|
clusterInitJoiner = &clusterFake{}
|
||||||
metadataAPI = &providerMetadataFake{}
|
metadataAPI = &providerMetadataFake{}
|
||||||
cloudLogger = &logging.NopLogger{}
|
cloudLogger = &logging.NopLogger{}
|
||||||
var simulatedTPMCloser io.Closer
|
var simulatedTPMCloser io.Closer
|
||||||
openTPM, simulatedTPMCloser = simulator.NewSimulatedTPMOpenFunc()
|
openDevice, simulatedTPMCloser = simulator.NewSimulatedTPMOpenFunc()
|
||||||
defer simulatedTPMCloser.Close()
|
defer simulatedTPMCloser.Close()
|
||||||
fs = afero.NewMemMapFs()
|
fs = afero.NewMemMapFs()
|
||||||
}
|
}
|
||||||
|
|
||||||
fileHandler := file.NewHandler(fs)
|
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/logging"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"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/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
@ -25,7 +26,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"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,
|
kube clusterInitJoiner, metadata metadataAPI,
|
||||||
bindIP, bindPort string, log *logger.Logger,
|
bindIP, bindPort string, log *logger.Logger,
|
||||||
cloudLogger logging.CloudLogger,
|
cloudLogger logging.CloudLogger,
|
||||||
@ -44,7 +45,7 @@ func run(issuer atls.Issuer, tpm vtpm.TPMOpenFunc, fileHandler file.Handler,
|
|||||||
cloudLogger.Disclose("Disk UUID: " + uuid)
|
cloudLogger.Disclose("Disk UUID: " + uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeBootstrapped, err := vtpm.IsNodeBootstrapped(tpm)
|
nodeBootstrapped, err := initialize.IsNodeBootstrapped(openDevice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.With(zap.Error(err)).Fatalf("Failed to check if node was previously bootstrapped")
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeLock := nodelock.New(tpm)
|
nodeLock := nodelock.New(openDevice)
|
||||||
initServer, err := initserver.New(context.Background(), nodeLock, kube, issuer, fileHandler, metadata, log)
|
initServer, err := initserver.New(context.Background(), nodeLock, kube, issuer, fileHandler, metadata, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.With(zap.Error(err)).Fatalf("Failed to create init server")
|
log.With(zap.Error(err)).Fatalf("Failed to create init server")
|
||||||
|
@ -5,5 +5,8 @@ go_library(
|
|||||||
srcs = ["nodelock.go"],
|
srcs = ["nodelock.go"],
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock",
|
importpath = "github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock",
|
||||||
visibility = ["//bootstrapper:__subpackages__"],
|
visibility = ["//bootstrapper:__subpackages__"],
|
||||||
deps = ["//internal/attestation/vtpm"],
|
deps = [
|
||||||
|
"//internal/attestation/initialize",
|
||||||
|
"//internal/attestation/vtpm",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ package nodelock
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,5 +41,5 @@ func (l *Lock) TryLockOnce(clusterID []byte) (bool, error) {
|
|||||||
return false, nil
|
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
|
oldExpected := m[pcrIndex].Expected
|
||||||
expectedPcr := sha256.Sum256(append(oldExpected[:], hashedInput[:]...))
|
expectedPcr := sha256.Sum256(append(oldExpected[:], hashedInput[:]...))
|
||||||
m[pcrIndex] = measurements.Measurement{
|
m[pcrIndex] = measurements.Measurement{
|
||||||
Expected: expectedPcr,
|
Expected: expectedPcr[:],
|
||||||
ValidationOpt: m[pcrIndex].ValidationOpt,
|
ValidationOpt: m[pcrIndex].ValidationOpt,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -132,7 +132,7 @@ func TestValidatorUpdateInitPCRs(t *testing.T) {
|
|||||||
case i == int(measurements.PCRIndexClusterID):
|
case i == int(measurements.PCRIndexClusterID):
|
||||||
pcr, ok := m[uint32(i)]
|
pcr, ok := m[uint32(i)]
|
||||||
assert.True(ok)
|
assert.True(ok)
|
||||||
assert.Equal(pcrZeroUpdatedOne, pcr.Expected)
|
assert.Equal(pcrZeroUpdatedOne[:], pcr.Expected)
|
||||||
|
|
||||||
case i == int(measurements.PCRIndexOwnerID) && tc.ownerID == "":
|
case i == int(measurements.PCRIndexOwnerID) && tc.ownerID == "":
|
||||||
// should be deleted
|
// should be deleted
|
||||||
@ -142,7 +142,7 @@ func TestValidatorUpdateInitPCRs(t *testing.T) {
|
|||||||
case i == int(measurements.PCRIndexOwnerID):
|
case i == int(measurements.PCRIndexOwnerID):
|
||||||
pcr, ok := m[uint32(i)]
|
pcr, ok := m[uint32(i)]
|
||||||
assert.True(ok)
|
assert.True(ok)
|
||||||
assert.Equal(pcrZeroUpdatedOne, pcr.Expected)
|
assert.Equal(pcrZeroUpdatedOne[:], pcr.Expected)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if i >= 17 && i <= 22 {
|
if i >= 17 && i <= 22 {
|
||||||
|
@ -69,6 +69,7 @@ go_library(
|
|||||||
"terraform/openstack/modules/loadbalancer/variables.tf",
|
"terraform/openstack/modules/loadbalancer/variables.tf",
|
||||||
"terraform/openstack/outputs.tf",
|
"terraform/openstack/outputs.tf",
|
||||||
"terraform/openstack/variables.tf",
|
"terraform/openstack/variables.tf",
|
||||||
|
"terraform/qemu/modules/instance_group/tdx_domain.xsl",
|
||||||
],
|
],
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/terraform",
|
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/terraform",
|
||||||
visibility = ["//cli:__subpackages__"],
|
visibility = ["//cli:__subpackages__"],
|
||||||
|
@ -82,22 +82,6 @@
|
|||||||
<xsl:template match="/domain/vcpu">
|
<xsl:template match="/domain/vcpu">
|
||||||
<vcpu placement="static"><xsl:apply-templates select="@*|node()"/></vcpu>
|
<vcpu placement="static"><xsl:apply-templates select="@*|node()"/></vcpu>
|
||||||
</xsl:template>
|
</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">
|
<xsl:template match="/domain/devices/console">
|
||||||
<console type="pty">
|
<console type="pty">
|
||||||
<target type="virtio" port="1" />
|
<target type="virtio" port="1" />
|
||||||
|
@ -12,6 +12,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//disk-mapper/internal/systemd",
|
"//disk-mapper/internal/systemd",
|
||||||
"//internal/attestation",
|
"//internal/attestation",
|
||||||
|
"//internal/attestation/initialize",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/cloud/metadata",
|
"//internal/cloud/metadata",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/disk-mapper/internal/systemd"
|
"github.com/edgelesssys/constellation/v2/disk-mapper/internal/systemd"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
"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/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||||
@ -109,7 +110,7 @@ func (s *Manager) PrepareExistingDisk(recover RecoveryDoer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// taint the node as initialized
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
go.mod
2
go.mod
@ -70,6 +70,7 @@ require (
|
|||||||
github.com/docker/docker v23.0.3+incompatible
|
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/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-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/fsnotify/fsnotify v1.6.0
|
||||||
github.com/go-playground/locales v0.14.1
|
github.com/go-playground/locales v0.14.1
|
||||||
github.com/go-playground/universal-translator v0.18.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/theupdateframework/go-tuf v0.5.2 // indirect
|
||||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||||
github.com/transparency-dev/merkle v0.0.1 // 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/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // 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/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 h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=
|
||||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f/go.mod h1:hX9gZBSvliJcBEAyrJDh7990hLRg/Is+6PBpDZWSMoc=
|
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/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||||
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
|
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 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
|
||||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
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/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/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.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
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/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/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-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/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible // 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/theupdateframework/go-tuf v0.5.2 // indirect
|
||||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||||
github.com/transparency-dev/merkle v0.0.1 // 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/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // 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/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 h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=
|
||||||
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f/go.mod h1:hX9gZBSvliJcBEAyrJDh7990hLRg/Is+6PBpDZWSMoc=
|
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/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||||
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
|
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 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
|
||||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
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/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/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.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
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
|
package attestation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +43,47 @@ const (
|
|||||||
MeasurementSecretContext = "measurementSecret"
|
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.
|
// DeriveClusterID derives the cluster ID from a salt and secret value.
|
||||||
func DeriveClusterID(secret, salt []byte) ([]byte, error) {
|
func DeriveClusterID(secret, salt []byte) ([]byte, error) {
|
||||||
return crypto.DeriveKey(secret, salt, []byte(crypto.DEKPrefix+clusterIDContext), crypto.DerivedKeyLengthDefault)
|
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
|
package attestation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/crypto/testvector"
|
"github.com/edgelesssys/constellation/v2/internal/crypto/testvector"
|
||||||
@ -31,3 +32,48 @@ func TestDeriveClusterID(t *testing.T) {
|
|||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
assert.NotEqual(clusterID, clusterIDdiff)
|
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",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/aws",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
"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/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ type Issuer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer creates a new OpenVTPM based issuer for AWS.
|
// NewIssuer creates a new OpenVTPM based issuer for AWS.
|
||||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
func NewIssuer(log attestation.Logger) *Issuer {
|
||||||
return &Issuer{
|
return &Issuer{
|
||||||
Issuer: vtpm.NewIssuer(
|
Issuer: vtpm.NewIssuer(
|
||||||
vtpm.OpenVTPM,
|
vtpm.OpenVTPM,
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
awsConfig "github.com/aws/aws-sdk-go-v2/config"
|
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/feature/ec2/imds"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
"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/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
@ -30,7 +31,7 @@ type Validator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator create a new Validator structure and returns it.
|
// 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{}
|
||||||
v.Validator = vtpm.NewValidator(
|
v.Validator = vtpm.NewValidator(
|
||||||
cfg.Measurements,
|
cfg.Measurements,
|
||||||
|
@ -14,6 +14,7 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/cloud/azure",
|
"//internal/cloud/azure",
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
"github.com/edgelesssys/go-azguestattestation/maa"
|
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||||
@ -30,7 +31,7 @@ type Issuer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer initializes a new Azure Issuer.
|
// NewIssuer initializes a new Azure Issuer.
|
||||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
func NewIssuer(log attestation.Logger) *Issuer {
|
||||||
i := &Issuer{
|
i := &Issuer{
|
||||||
imds: newIMDSClient(),
|
imds: newIMDSClient(),
|
||||||
maa: newMAAClient(),
|
maa: newMAAClient(),
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
@ -38,11 +39,11 @@ type Validator struct {
|
|||||||
|
|
||||||
config *config.AzureSEVSNP
|
config *config.AzureSEVSNP
|
||||||
|
|
||||||
log vtpm.AttestationLogger
|
log attestation.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator initializes a new Azure validator with the provided PCR values.
|
// 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 {
|
if log == nil {
|
||||||
log = nopAttestationLogger{}
|
log = nopAttestationLogger{}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/trustedlaunch",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/trustedlaunch",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/crypto",
|
"//internal/crypto",
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
tpmclient "github.com/google/go-tpm-tools/client"
|
tpmclient "github.com/google/go-tpm-tools/client"
|
||||||
@ -34,7 +35,7 @@ type Issuer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer initializes a new Azure Issuer.
|
// NewIssuer initializes a new Azure Issuer.
|
||||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
func NewIssuer(log attestation.Logger) *Issuer {
|
||||||
i := &Issuer{
|
i := &Issuer{
|
||||||
hClient: &http.Client{},
|
hClient: &http.Client{},
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
certutil "github.com/edgelesssys/constellation/v2/internal/crypto"
|
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.
|
// 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 := x509.NewCertPool()
|
||||||
rootPool.AddCert(ameRoot)
|
rootPool.AddCert(ameRoot)
|
||||||
v := &Validator{roots: rootPool}
|
v := &Validator{roots: rootPool}
|
||||||
|
@ -8,12 +8,13 @@ go_library(
|
|||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/aws",
|
"//internal/attestation/aws",
|
||||||
"//internal/attestation/azure/snp",
|
"//internal/attestation/azure/snp",
|
||||||
"//internal/attestation/azure/trustedlaunch",
|
"//internal/attestation/azure/trustedlaunch",
|
||||||
"//internal/attestation/gcp",
|
"//internal/attestation/gcp",
|
||||||
"//internal/attestation/qemu",
|
"//internal/attestation/qemu",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/tdx",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
],
|
],
|
||||||
|
@ -10,18 +10,19 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"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/aws"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp"
|
"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/azure/trustedlaunch"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/gcp"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/gcp"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
"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/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Issuer returns the issuer for the given 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 {
|
switch attestationVariant {
|
||||||
case variant.AWSNitroTPM{}:
|
case variant.AWSNitroTPM{}:
|
||||||
return aws.NewIssuer(log), nil
|
return aws.NewIssuer(log), nil
|
||||||
@ -33,6 +34,8 @@ func Issuer(attestationVariant variant.Variant, log vtpm.AttestationLogger) (atl
|
|||||||
return gcp.NewIssuer(log), nil
|
return gcp.NewIssuer(log), nil
|
||||||
case variant.QEMUVTPM{}:
|
case variant.QEMUVTPM{}:
|
||||||
return qemu.NewIssuer(log), nil
|
return qemu.NewIssuer(log), nil
|
||||||
|
case variant.QEMUTDX{}:
|
||||||
|
return tdx.NewIssuer(log), nil
|
||||||
case variant.Dummy{}:
|
case variant.Dummy{}:
|
||||||
return atls.NewFakeIssuer(variant.Dummy{}), nil
|
return atls.NewFakeIssuer(variant.Dummy{}), nil
|
||||||
default:
|
default:
|
||||||
@ -41,7 +44,7 @@ func Issuer(attestationVariant variant.Variant, log vtpm.AttestationLogger) (atl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validator returns the validator for the given variant.
|
// 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) {
|
switch cfg := cfg.(type) {
|
||||||
case *config.AWSNitroTPM:
|
case *config.AWSNitroTPM:
|
||||||
return aws.NewValidator(cfg, log), nil
|
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
|
return gcp.NewValidator(cfg, log), nil
|
||||||
case *config.QEMUVTPM:
|
case *config.QEMUVTPM:
|
||||||
return qemu.NewValidator(cfg, log), nil
|
return qemu.NewValidator(cfg, log), nil
|
||||||
|
case *config.QEMUTDX:
|
||||||
|
return tdx.NewValidator(cfg, log), nil
|
||||||
case *config.DummyCfg:
|
case *config.DummyCfg:
|
||||||
return atls.NewFakeValidator(variant.Dummy{}), nil
|
return atls.NewFakeValidator(variant.Dummy{}), nil
|
||||||
default:
|
default:
|
||||||
|
@ -11,6 +11,7 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/gcp",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/gcp",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
"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/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
tpmclient "github.com/google/go-tpm-tools/client"
|
tpmclient "github.com/google/go-tpm-tools/client"
|
||||||
@ -26,7 +27,7 @@ type Issuer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer initializes a new GCP Issuer.
|
// NewIssuer initializes a new GCP Issuer.
|
||||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
func NewIssuer(log attestation.Logger) *Issuer {
|
||||||
return &Issuer{
|
return &Issuer{
|
||||||
Issuer: vtpm.NewIssuer(
|
Issuer: vtpm.NewIssuer(
|
||||||
vtpm.OpenVTPM,
|
vtpm.OpenVTPM,
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
|
|
||||||
compute "cloud.google.com/go/compute/apiv1"
|
compute "cloud.google.com/go/compute/apiv1"
|
||||||
"cloud.google.com/go/compute/apiv1/computepb"
|
"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/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"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.
|
// 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{
|
v := &Validator{
|
||||||
restClient: newInstanceClient,
|
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
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package vtpm
|
package initialize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"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.
|
// byteArrayCompositeLit returns a *ast.CompositeLit representing a byte array literal.
|
||||||
// The returned literal is of the form:
|
// The returned literal is of the form:
|
||||||
// [32]byte{ 0x01, 0x02, 0x03, ... }.
|
// []byte{ 0x01, 0x02, 0x03, ... }.
|
||||||
func byteArrayCompositeLit(hex [32]byte) *ast.CompositeLit {
|
func byteArrayCompositeLit(hex []byte) *ast.CompositeLit {
|
||||||
var elts []ast.Expr
|
var elts []ast.Expr
|
||||||
// create list of byte literals
|
// create list of byte literals
|
||||||
for _, b := range hex {
|
for _, b := range hex {
|
||||||
@ -183,10 +183,9 @@ func byteArrayCompositeLit(hex [32]byte) *ast.CompositeLit {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// create the composite literal
|
// 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{
|
return &ast.CompositeLit{
|
||||||
Type: &ast.ArrayType{
|
Type: &ast.ArrayType{
|
||||||
Len: ast.NewIdent("32"),
|
|
||||||
Elt: ast.NewIdent("byte"),
|
Elt: ast.NewIdent("byte"),
|
||||||
},
|
},
|
||||||
Elts: elts,
|
Elts: elts,
|
||||||
@ -197,7 +196,7 @@ func byteArrayCompositeLit(hex [32]byte) *ast.CompositeLit {
|
|||||||
// The returned expression is of the form:
|
// The returned expression is of the form:
|
||||||
//
|
//
|
||||||
// 0: {
|
// 0: {
|
||||||
// Expected: [32]byte{ 0x01, 0x02, 0x03, ... },
|
// Expected: []byte{ 0x01, 0x02, 0x03, ... },
|
||||||
// WarnOnly: false,
|
// WarnOnly: false,
|
||||||
// },
|
// },
|
||||||
func measurementsEntryKeyValueExpr(pcr uint32, measuremnt measurements.Measurement) *ast.KeyValueExpr {
|
func measurementsEntryKeyValueExpr(pcr uint32, measuremnt measurements.Measurement) *ast.KeyValueExpr {
|
||||||
@ -235,11 +234,11 @@ func measurementsEntryKeyValueExpr(pcr uint32, measuremnt measurements.Measureme
|
|||||||
//
|
//
|
||||||
// M{
|
// M{
|
||||||
// 0: {
|
// 0: {
|
||||||
// Expected: [32]byte{ 0x01, 0x02, 0x03, ... },
|
// Expected: []byte{ 0x01, 0x02, 0x03, ... },
|
||||||
// WarnOnly: false,
|
// WarnOnly: false,
|
||||||
// },
|
// },
|
||||||
// 1: {
|
// 1: {
|
||||||
// Expected: [32]byte{ 0x01, 0x02, 0x03, ... },
|
// Expected: []byte{ 0x01, 0x02, 0x03, ... },
|
||||||
// WarnOnly: false,
|
// WarnOnly: false,
|
||||||
// },
|
// },
|
||||||
// ...
|
// ...
|
||||||
|
@ -43,6 +43,12 @@ const (
|
|||||||
// The value used to extend is derived from Constellation's master key.
|
// The value used to extend is derived from Constellation's master key.
|
||||||
// TODO: move to stable, non-debug PCR before use.
|
// TODO: move to stable, non-debug PCR before use.
|
||||||
PCRIndexOwnerID = tpmutil.Handle(16)
|
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.
|
// 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 {
|
for k, v := range *m {
|
||||||
otherExpected := other[k].Expected
|
otherExpected := other[k].Expected
|
||||||
if !bytes.Equal(v.Expected[:], otherExpected[:]) {
|
if !bytes.Equal(v.Expected, otherExpected) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if v.ValidationOpt != other[k].ValidationOpt {
|
if v.ValidationOpt != other[k].ValidationOpt {
|
||||||
@ -177,10 +183,45 @@ func (m *M) SetEnforced(enforced []uint32) error {
|
|||||||
return nil
|
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.
|
// Measurement wraps expected PCR value and whether it is enforced.
|
||||||
type Measurement struct {
|
type Measurement struct {
|
||||||
// Expected measurement value.
|
// 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 indicates how measurement mismatches should be handled.
|
||||||
ValidationOpt MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`
|
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))
|
return fmt.Errorf("invalid measurement: invalid length: %d", len(expected))
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Expected = *(*[32]byte)(expected)
|
m.Expected = expected
|
||||||
m.ValidationOpt = eM.WarnOnly
|
m.ValidationOpt = eM.WarnOnly
|
||||||
|
|
||||||
return nil
|
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.
|
// WithAllBytes returns a measurement value where all 32 bytes are set to b.
|
||||||
func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement {
|
func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement {
|
||||||
return Measurement{
|
return Measurement{
|
||||||
Expected: *(*[32]byte)(bytes.Repeat([]byte{b}, 32)),
|
Expected: bytes.Repeat([]byte{b}, 32),
|
||||||
ValidationOpt: validationOpt,
|
ValidationOpt: validationOpt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,7 +331,7 @@ func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement
|
|||||||
// PlaceHolderMeasurement returns a measurement with placeholder values for Expected.
|
// PlaceHolderMeasurement returns a measurement with placeholder values for Expected.
|
||||||
func PlaceHolderMeasurement() Measurement {
|
func PlaceHolderMeasurement() Measurement {
|
||||||
return Measurement{
|
return Measurement{
|
||||||
Expected: *(*[32]byte)(bytes.Repeat([]byte{0x12, 0x34}, 16)),
|
Expected: bytes.Repeat([]byte{0x12, 0x34}, 16),
|
||||||
ValidationOpt: Enforce,
|
ValidationOpt: Enforce,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,6 +357,18 @@ func getFromURL(ctx context.Context, client *http.Client, sourceURL *url.URL) ([
|
|||||||
return content, nil
|
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 {
|
type encodedMeasurement struct {
|
||||||
Expected string `json:"expected" yaml:"expected"`
|
Expected string `json:"expected" yaml:"expected"`
|
||||||
WarnOnly MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`
|
WarnOnly MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`
|
||||||
|
@ -16,19 +16,19 @@ import "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|||||||
//go:generate measurement-generator
|
//go:generate measurement-generator
|
||||||
|
|
||||||
// DefaultsFor provides the default measurements for given cloud provider.
|
// DefaultsFor provides the default measurements for given cloud provider.
|
||||||
func DefaultsFor(provider cloudprovider.Provider) M {
|
func DefaultsFor(attestationVariant variant.Variant) M {
|
||||||
switch provider {
|
switch provider {
|
||||||
case cloudprovider.AWS:
|
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:
|
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:
|
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:
|
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:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
@ -9,6 +9,7 @@ package measurements
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -30,14 +31,14 @@ func TestMarshal(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
"measurement": {
|
"measurement": {
|
||||||
m: 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",
|
wantYAML: "expected: \"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35\"\nwarnOnly: false",
|
||||||
wantJSON: `{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35","warnOnly":false}`,
|
wantJSON: `{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35","warnOnly":false}`,
|
||||||
},
|
},
|
||||||
"warn only": {
|
"warn only": {
|
||||||
m: Measurement{
|
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,
|
ValidationOpt: WarnOnly,
|
||||||
},
|
},
|
||||||
wantYAML: "expected: \"0102030400000000000000000000000000000000000000000000000000000000\"\nwarnOnly: true",
|
wantYAML: "expected: \"0102030400000000000000000000000000000000000000000000000000000000\"\nwarnOnly: true",
|
||||||
@ -81,10 +82,10 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
inputJSON: `{"2":{"expected":"/V3p3zUOO8RBCsBrv+XM3rk/U7nvUSOfdSzmnbxgDzU="},"3":{"expected":"1aRJbSHeyaUljdsZxv61O7TTwEY/5gfySI3fTxAG754="}}`,
|
inputJSON: `{"2":{"expected":"/V3p3zUOO8RBCsBrv+XM3rk/U7nvUSOfdSzmnbxgDzU="},"3":{"expected":"1aRJbSHeyaUljdsZxv61O7TTwEY/5gfySI3fTxAG754="}}`,
|
||||||
wantMeasurements: M{
|
wantMeasurements: M{
|
||||||
2: {
|
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: {
|
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"}}`,
|
inputJSON: `{"2":{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef51239f752ce69dbc600f35"},"3":{"expected":"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463fe607f2488ddf4f1006ef9e"}}`,
|
||||||
wantMeasurements: M{
|
wantMeasurements: M{
|
||||||
2: {
|
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: {
|
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="}}`,
|
inputJSON: `{"2":{"expected":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},"3":{"expected":"AQIDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}}`,
|
||||||
wantMeasurements: M{
|
wantMeasurements: M{
|
||||||
2: {
|
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: {
|
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="}`,
|
inputJSON: `{"2":"/V3p3zUOO8RBCsBrv+XM3rk/U7nvUSOfdSzmnbxgDzU=","3":"1aRJbSHeyaUljdsZxv61O7TTwEY/5gfySI3fTxAG754="}`,
|
||||||
wantMeasurements: M{
|
wantMeasurements: M{
|
||||||
2: {
|
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: {
|
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"}}`,
|
inputJSON: `{"2":{"expected":"fd5de9df350e3bc4410ac06bbfe5ccdeb93f53b9ef"},"3":{"expected":"d5a4496d21dec9a5258ddb19c6feb53bb4d3c0463f"}}`,
|
||||||
wantErr: true,
|
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": {
|
"invalid length base64": {
|
||||||
inputYAML: "2:\n expected: \"AA==\"\n3:\n expected: \"AQIDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\"",
|
inputYAML: "2:\n expected: \"AA==\"\n3:\n expected: \"AQIDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\"",
|
||||||
inputJSON: `{"2":{"expected":"AA=="},"3":{"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)
|
err := json.Unmarshal([]byte(tc.inputJSON), &m)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
|
fmt.Println(err)
|
||||||
assert.Error(err, "json.Unmarshal should have failed")
|
assert.Error(err, "json.Unmarshal should have failed")
|
||||||
} else {
|
} else {
|
||||||
require.NoError(err, "json.Unmarshal failed")
|
require.NoError(err, "json.Unmarshal failed")
|
||||||
@ -200,10 +219,10 @@ func TestEncodeM(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"output is sorted": {
|
"output is sorted": {
|
||||||
m: M{
|
m: M{
|
||||||
3: {},
|
3: WithAllBytes(0, false),
|
||||||
1: {},
|
1: WithAllBytes(0, false),
|
||||||
11: {},
|
11: WithAllBytes(0, false),
|
||||||
2: {},
|
2: WithAllBytes(0, false),
|
||||||
},
|
},
|
||||||
want: `1:
|
want: `1:
|
||||||
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
@ -605,7 +624,7 @@ func TestWithAllBytes(t *testing.T) {
|
|||||||
b: 0x00,
|
b: 0x00,
|
||||||
warnOnly: true,
|
warnOnly: true,
|
||||||
wantMeasurement: Measurement{
|
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,
|
ValidationOpt: WarnOnly,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -613,7 +632,7 @@ func TestWithAllBytes(t *testing.T) {
|
|||||||
b: 0x00,
|
b: 0x00,
|
||||||
warnOnly: false,
|
warnOnly: false,
|
||||||
wantMeasurement: Measurement{
|
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,
|
ValidationOpt: Enforce,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -621,7 +640,7 @@ func TestWithAllBytes(t *testing.T) {
|
|||||||
b: 0x01,
|
b: 0x01,
|
||||||
warnOnly: true,
|
warnOnly: true,
|
||||||
wantMeasurement: Measurement{
|
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,
|
ValidationOpt: WarnOnly,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -629,7 +648,7 @@ func TestWithAllBytes(t *testing.T) {
|
|||||||
b: 0x01,
|
b: 0x01,
|
||||||
warnOnly: false,
|
warnOnly: false,
|
||||||
wantMeasurement: Measurement{
|
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,
|
ValidationOpt: Enforce,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -637,7 +656,7 @@ func TestWithAllBytes(t *testing.T) {
|
|||||||
b: 0xFF,
|
b: 0xFF,
|
||||||
warnOnly: true,
|
warnOnly: true,
|
||||||
wantMeasurement: Measurement{
|
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,
|
ValidationOpt: WarnOnly,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -645,7 +664,7 @@ func TestWithAllBytes(t *testing.T) {
|
|||||||
b: 0xFF,
|
b: 0xFF,
|
||||||
warnOnly: false,
|
warnOnly: false,
|
||||||
wantMeasurement: Measurement{
|
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,
|
ValidationOpt: Enforce,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,7 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/qemu",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/qemu",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/variant",
|
"//internal/variant",
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||||
tpmclient "github.com/google/go-tpm-tools/client"
|
tpmclient "github.com/google/go-tpm-tools/client"
|
||||||
@ -22,7 +23,7 @@ type Issuer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer initializes a new QEMU Issuer.
|
// NewIssuer initializes a new QEMU Issuer.
|
||||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
func NewIssuer(log attestation.Logger) *Issuer {
|
||||||
return &Issuer{
|
return &Issuer{
|
||||||
Issuer: vtpm.NewIssuer(
|
Issuer: vtpm.NewIssuer(
|
||||||
vtpm.OpenVTPM,
|
vtpm.OpenVTPM,
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
"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.
|
// 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{
|
return &Validator{
|
||||||
Validator: vtpm.NewValidator(
|
Validator: vtpm.NewValidator(
|
||||||
cfg.Measurements,
|
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",
|
name = "vtpm",
|
||||||
srcs = [
|
srcs = [
|
||||||
"attestation.go",
|
"attestation.go",
|
||||||
"initialize.go",
|
|
||||||
"vtpm.go",
|
"vtpm.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/vtpm",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/vtpm",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"@com_github_google_go_tpm//tpm2",
|
"@com_github_google_go_tpm//tpm2",
|
||||||
"@com_github_google_go_tpm_tools//client",
|
"@com_github_google_go_tpm_tools//client",
|
||||||
@ -24,7 +24,6 @@ go_test(
|
|||||||
name = "vtpm_test",
|
name = "vtpm_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"attestation_test.go",
|
"attestation_test.go",
|
||||||
"initialize_test.go",
|
|
||||||
"vtpm_test.go",
|
"vtpm_test.go",
|
||||||
],
|
],
|
||||||
embed = [":vtpm"],
|
embed = [":vtpm"],
|
||||||
@ -34,6 +33,7 @@ go_test(
|
|||||||
"//conditions:default": ["disable_tpm_simulator"],
|
"//conditions:default": ["disable_tpm_simulator"],
|
||||||
}),
|
}),
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation/initialize",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/attestation/simulator",
|
"//internal/attestation/simulator",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -21,6 +20,7 @@ import (
|
|||||||
tpmServer "github.com/google/go-tpm-tools/server"
|
tpmServer "github.com/google/go-tpm-tools/server"
|
||||||
"github.com/google/go-tpm/tpm2"
|
"github.com/google/go-tpm/tpm2"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -66,12 +66,6 @@ type (
|
|||||||
ValidateCVM func(attestation AttestationDocument, state *attest.MachineState) error
|
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.
|
// AttestationDocument contains the TPM attestation with signed user data.
|
||||||
type AttestationDocument struct {
|
type AttestationDocument struct {
|
||||||
// Attestation contains the TPM event log, PCR values and quotes, and public key of the key used to sign the attestation.
|
// 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
|
openTPM TPMOpenFunc
|
||||||
getAttestationKey GetTPMAttestationKey
|
getAttestationKey GetTPMAttestationKey
|
||||||
getInstanceInfo GetInstanceInfo
|
getInstanceInfo GetInstanceInfo
|
||||||
log AttestationLogger
|
log attestation.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer returns a new Issuer.
|
// NewIssuer returns a new Issuer.
|
||||||
func NewIssuer(
|
func NewIssuer(
|
||||||
openTPM TPMOpenFunc, getAttestationKey GetTPMAttestationKey,
|
openTPM TPMOpenFunc, getAttestationKey GetTPMAttestationKey,
|
||||||
getInstanceInfo GetInstanceInfo, log AttestationLogger,
|
getInstanceInfo GetInstanceInfo, log attestation.Logger,
|
||||||
) *Issuer {
|
) *Issuer {
|
||||||
if log == nil {
|
if log == nil {
|
||||||
log = &nopAttestationLogger{}
|
log = &attestation.NOPLogger{}
|
||||||
}
|
}
|
||||||
return &Issuer{
|
return &Issuer{
|
||||||
openTPM: openTPM,
|
openTPM: openTPM,
|
||||||
@ -129,7 +123,7 @@ func (i *Issuer) Issue(ctx context.Context, userData []byte, nonce []byte) (res
|
|||||||
defer aK.Close()
|
defer aK.Close()
|
||||||
|
|
||||||
// Create an attestation using the loaded key
|
// Create an attestation using the loaded key
|
||||||
extraData := makeExtraData(userData, nonce)
|
extraData := attestation.MakeExtraData(userData, nonce)
|
||||||
tpmAttestation, err := aK.Attest(tpmClient.AttestOpts{Nonce: extraData})
|
tpmAttestation, err := aK.Attest(tpmClient.AttestOpts{Nonce: extraData})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("creating attestation: %w", err)
|
return nil, fmt.Errorf("creating attestation: %w", err)
|
||||||
@ -162,15 +156,15 @@ type Validator struct {
|
|||||||
getTrustedKey GetTPMTrustedAttestationPublicKey
|
getTrustedKey GetTPMTrustedAttestationPublicKey
|
||||||
validateCVM ValidateCVM
|
validateCVM ValidateCVM
|
||||||
|
|
||||||
log AttestationLogger
|
log attestation.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator returns a new Validator.
|
// NewValidator returns a new Validator.
|
||||||
func NewValidator(expected measurements.M, getTrustedKey GetTPMTrustedAttestationPublicKey,
|
func NewValidator(expected measurements.M, getTrustedKey GetTPMTrustedAttestationPublicKey,
|
||||||
validateCVM ValidateCVM, log AttestationLogger,
|
validateCVM ValidateCVM, log attestation.Logger,
|
||||||
) *Validator {
|
) *Validator {
|
||||||
if log == nil {
|
if log == nil {
|
||||||
log = &nopAttestationLogger{}
|
log = &attestation.NOPLogger{}
|
||||||
}
|
}
|
||||||
return &Validator{
|
return &Validator{
|
||||||
expected: expected,
|
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)
|
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
|
// Verify and retrieve the trusted attestation public key using the provided instance info
|
||||||
aKP, err := v.getTrustedKey(ctx, attDoc, extraData)
|
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))
|
return nil, fmt.Errorf("invalid measurement: invalid length: %d", len(pcr))
|
||||||
}
|
}
|
||||||
m[i] = measurements.Measurement{
|
m[i] = measurements.Measurement{
|
||||||
Expected: *(*[32]byte)(pcr),
|
Expected: pcr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeExtraData(userData []byte, nonce []byte) []byte {
|
|
||||||
data := append([]byte{}, userData...)
|
|
||||||
data = append(data, nonce...)
|
|
||||||
digest := sha256.Sum256(data)
|
|
||||||
return digest[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// nopAttestationLogger is a no-op implementation of AttestationLogger.
|
|
||||||
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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"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/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||||
tpmsim "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)
|
require.Equal(challenge, out)
|
||||||
|
|
||||||
// validation must fail after bootstrapping (change of enforced PCR)
|
// 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)
|
attDocBootstrappedRaw, err := issuer.Issue(ctx, challenge, nonce)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
_, err = validator.Validate(ctx, attDocBootstrappedRaw, nonce)
|
_, err = validator.Validate(ctx, attDocBootstrappedRaw, nonce)
|
||||||
@ -121,19 +122,19 @@ func TestValidate(t *testing.T) {
|
|||||||
0: measurements.WithAllBytes(0x00, measurements.WarnOnly),
|
0: measurements.WithAllBytes(0x00, measurements.WarnOnly),
|
||||||
1: measurements.WithAllBytes(0x00, measurements.WarnOnly),
|
1: measurements.WithAllBytes(0x00, measurements.WarnOnly),
|
||||||
2: measurements.Measurement{
|
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,
|
ValidationOpt: measurements.WarnOnly,
|
||||||
},
|
},
|
||||||
3: measurements.Measurement{
|
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,
|
ValidationOpt: measurements.WarnOnly,
|
||||||
},
|
},
|
||||||
4: measurements.Measurement{
|
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,
|
ValidationOpt: measurements.WarnOnly,
|
||||||
},
|
},
|
||||||
5: measurements.Measurement{
|
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,
|
ValidationOpt: measurements.WarnOnly,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -202,7 +203,7 @@ func TestValidate(t *testing.T) {
|
|||||||
validator: NewValidator(
|
validator: NewValidator(
|
||||||
measurements.M{
|
measurements.M{
|
||||||
0: measurements.Measurement{
|
0: measurements.Measurement{
|
||||||
Expected: [32]byte{0xFF},
|
Expected: []byte{0xFF},
|
||||||
ValidationOpt: measurements.Enforce,
|
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 (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.uber.org/goleak"
|
"go.uber.org/goleak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
goleak.VerifyTestMain(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
|
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 {
|
func toPtr[T any](v T) *T {
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ const (
|
|||||||
azureSEVSNP = "azure-sev-snp"
|
azureSEVSNP = "azure-sev-snp"
|
||||||
azureTrustedLaunch = "azure-trustedlaunch"
|
azureTrustedLaunch = "azure-trustedlaunch"
|
||||||
qemuVTPM = "qemu-vtpm"
|
qemuVTPM = "qemu-vtpm"
|
||||||
|
qemuTDX = "qemu-tdx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Getter returns an ASN.1 Object Identifier.
|
// Getter returns an ASN.1 Object Identifier.
|
||||||
@ -72,6 +73,8 @@ func FromString(oid string) (Variant, error) {
|
|||||||
return AzureTrustedLaunch{}, nil
|
return AzureTrustedLaunch{}, nil
|
||||||
case qemuVTPM:
|
case qemuVTPM:
|
||||||
return QEMUVTPM{}, nil
|
return QEMUVTPM{}, nil
|
||||||
|
case qemuTDX:
|
||||||
|
return QEMUTDX{}, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unknown OID: %q", oid)
|
return nil, fmt.Errorf("unknown OID: %q", oid)
|
||||||
}
|
}
|
||||||
@ -183,3 +186,22 @@ func (QEMUVTPM) String() string {
|
|||||||
func (QEMUVTPM) Equal(other Getter) bool {
|
func (QEMUVTPM) Equal(other Getter) bool {
|
||||||
return other.OID().Equal(QEMUVTPM{}.OID())
|
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