Skip to content

Commit

Permalink
atls: probe for vTPM support
Browse files Browse the repository at this point in the history
  • Loading branch information
burgerdev committed Nov 1, 2024
1 parent bae04c4 commit 30ec538
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 5 deletions.
35 changes: 30 additions & 5 deletions internal/atls/issuer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package atls
import (
"fmt"
"log/slog"
"os"

"github.com/edgelesssys/contrast/internal/attestation/snp"
"github.com/edgelesssys/contrast/internal/attestation/tdx"
Expand All @@ -15,17 +16,41 @@ import (

// PlatformIssuer creates an attestation issuer for the current platform.
func PlatformIssuer(log *slog.Logger) (Issuer, error) {
cpuid.Detect()
var issuer Issuer
switch {
case cpuid.CPU.Supports(cpuid.SEV_SNP):
return snp.NewIssuer(
issuer = snp.NewIssuer(
logger.NewWithAttrs(logger.NewNamed(log, "issuer"), map[string]string{"tee-type": "snp"}),
), nil
)
case cpuid.CPU.Supports(cpuid.TDX_GUEST):
return tdx.NewIssuer(
issuer = tdx.NewIssuer(
logger.NewWithAttrs(logger.NewNamed(log, "issuer"), map[string]string{"tee-type": "tdx"}),
), nil
)
default:
return nil, fmt.Errorf("unsupported platform: %T", cpuid.CPU)
}

if hasTPM() {
issuer = &vtpmIssuer{Issuer: issuer}
}
return issuer, nil
}

var tpmDevice = "/dev/tpm0"

func hasTPM() bool {
f, err := os.Open(tpmDevice)
if err == nil {
f.Close()
return true
}
// If the device does not exist, we don't have a TPM.
// If the device exists but there is no backing TPM, the Open call fails with ENODEV.
return false
}

// vtpmIssuer issues attestation statements for VMs with a TPM.
// TODO(burgerdev): this is currently a mock that just delegates to an underlying issuer.
type vtpmIssuer struct {
Issuer
}
103 changes: 103 additions & 0 deletions internal/atls/issuer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2024 Edgeless Systems GmbH
// SPDX-License-Identifier: AGPL-3.0-only

package atls

import (
"log/slog"
"os"
"path/filepath"
"testing"

"github.com/edgelesssys/contrast/internal/attestation/snp"
"github.com/edgelesssys/contrast/internal/attestation/tdx"
"github.com/klauspost/cpuid/v2"
"github.com/stretchr/testify/require"
)

func TestPlatformIssuer(t *testing.T) {
d := t.TempDir()
tpmFile := filepath.Join(d, "tpm0")
f, err := os.Create(tpmFile)
require.NoError(t, err)
t.Cleanup(func() { f.Close() })

snpCPU := cpuid.CPUInfo{}
snpCPU.Enable(cpuid.SEV_SNP)

tdxCPU := cpuid.CPUInfo{}
tdxCPU.Enable(cpuid.TDX_GUEST)

for _, tc := range []struct {
name string
tpm string
cpu *cpuid.CPUInfo

expectIssuerType any
expectError bool
}{
{
name: "tpm-snp",
tpm: tpmFile,
cpu: &snpCPU,

expectIssuerType: &vtpmIssuer{},
},
{
name: "tpm-tdx",
tpm: tpmFile,
cpu: &tdxCPU,

expectIssuerType: &vtpmIssuer{},
},
{
name: "notpm-snp",
tpm: "/invalid",
cpu: &snpCPU,

expectIssuerType: &snp.Issuer{},
},
{
name: "notpm-tdx",
tpm: "/invalid",
cpu: &tdxCPU,

expectIssuerType: &tdx.Issuer{},
},
{
name: "notpm-notee",
tpm: "/invalid",
cpu: &cpuid.CPUInfo{},

expectError: true,
},
} {
t.Run(tc.name, func(t *testing.T) {
require := require.New(t)
savedCPU := cpuid.CPU
t.Cleanup(func() {
cpuid.CPU = savedCPU
})
if tc.cpu != nil {
cpuid.CPU = *tc.cpu
}

savedTPMDevice := tpmDevice
t.Cleanup(func() {
tpmDevice = savedTPMDevice
})
if tc.tpm != "" {
tpmDevice = tc.tpm
}

issuer, err := PlatformIssuer(slog.Default())
if tc.expectError {
require.Error(err)
return
}
require.NoError(err)

require.IsType(tc.expectIssuerType, issuer)
})
}
}

0 comments on commit 30ec538

Please sign in to comment.