Skip to content

Commit

Permalink
Implement support for "latest" placeholders for Azure TDX
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Weiße <[email protected]>
  • Loading branch information
daniel-weisse committed Jun 12, 2024
1 parent 2685666 commit f68709d
Show file tree
Hide file tree
Showing 15 changed files with 397 additions and 254 deletions.
4 changes: 2 additions & 2 deletions internal/api/attestationconfigapi/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ go_library(
srcs = [
"attestationconfigapi.go",
"fetcher.go",
"snp.go",
"version.go",
],
importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi",
visibility = ["//:__subpackages__"],
Expand All @@ -22,7 +22,7 @@ go_test(
name = "attestationconfigapi_test",
srcs = [
"fetcher_test.go",
"snp_test.go",
"version_test.go",
],
embed = [":attestationconfigapi"],
deps = [
Expand Down
1 change: 1 addition & 0 deletions internal/api/attestationconfigapi/cli/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ go_library(
deps = [
"//internal/api/attestationconfigapi",
"//internal/api/attestationconfigapi/cli/client",
"//internal/api/fetcher",
"//internal/attestation/variant",
"//internal/cloud/cloudprovider",
"//internal/constants",
Expand Down
10 changes: 5 additions & 5 deletions internal/attestation/azure/tdx/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ func (v *Validator) validateQuote(tdxQuote *tdx.QuoteV4) error {

if err := validate.TdxQuote(tdxQuote, &validate.Options{
HeaderOptions: validate.HeaderOptions{
MinimumQeSvn: v.cfg.QESVN,
MinimumPceSvn: v.cfg.PCESVN,
QeVendorID: v.cfg.QEVendorID,
MinimumQeSvn: v.cfg.QESVN.Value,
MinimumPceSvn: v.cfg.PCESVN.Value,
QeVendorID: v.cfg.QEVendorID.Value,
},
TdQuoteBodyOptions: validate.TdQuoteBodyOptions{
MinimumTeeTcbSvn: v.cfg.TEETCBSVN,
MinimumTeeTcbSvn: v.cfg.TEETCBSVN.Value,
MrSeam: v.cfg.MRSeam,
Xfam: v.cfg.XFAM,
Xfam: v.cfg.XFAM.Value,
},
}); err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions internal/config/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ go_test(
"//internal/cloud/cloudprovider",
"//internal/config/instancetypes",
"//internal/constants",
"//internal/encoding",
"//internal/file",
"//internal/semver",
"//internal/versions",
Expand Down
96 changes: 45 additions & 51 deletions internal/config/attestationversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,87 +9,81 @@ package config
import (
"encoding/json"
"fmt"
"math"
"strconv"
"strings"

"github.com/edgelesssys/constellation/v2/internal/encoding"
)

const placeholderVersionValue = 0
type versionValue interface {
encoding.HexBytes | uint8 | uint16
}

func placeholderVersionValue[T versionValue]() T {
var placeholder T
return placeholder
}

// NewLatestPlaceholderVersion returns the latest version with a placeholder version value.
func NewLatestPlaceholderVersion() AttestationVersion {
return AttestationVersion{
Value: placeholderVersionValue,
func NewLatestPlaceholderVersion[T versionValue]() AttestationVersion[T] {
return AttestationVersion[T]{
Value: placeholderVersionValue[T](),
WantLatest: true,
}
}

// AttestationVersion is a type that represents a version of a SNP.
type AttestationVersion struct {
Value uint8
// AttestationVersion holds version information.
type AttestationVersion[T versionValue] struct {
Value T
WantLatest bool
}

// MarshalYAML implements a custom marshaller to resolve "latest" values.
func (v AttestationVersion) MarshalYAML() (any, error) {
// MarshalYAML implements a custom marshaller to write "latest" as the type's value, if set.
func (v AttestationVersion[T]) MarshalYAML() (any, error) {
if v.WantLatest {
return "latest", nil
}
return v.Value, nil
}

// UnmarshalYAML implements a custom unmarshaller to resolve "atest" values.
func (v *AttestationVersion) UnmarshalYAML(unmarshal func(any) error) error {
var rawUnmarshal string
if err := unmarshal(&rawUnmarshal); err != nil {
return fmt.Errorf("raw unmarshal: %w", err)
}

return v.parseRawUnmarshal(rawUnmarshal)
// UnmarshalYAML implements a custom unmarshaller to resolve "latest" values.
func (v *AttestationVersion[T]) UnmarshalYAML(unmarshal func(any) error) error {
return v.unmarshal(unmarshal)
}

// MarshalJSON implements a custom marshaller to resolve "latest" values.
func (v AttestationVersion) MarshalJSON() ([]byte, error) {
// MarshalJSON implements a custom marshaller to write "latest" as the type's value, if set.
func (v AttestationVersion[T]) MarshalJSON() ([]byte, error) {
if v.WantLatest {
return json.Marshal("latest")
}
return json.Marshal(v.Value)
}

// UnmarshalJSON implements a custom unmarshaller to resolve "latest" values.
func (v *AttestationVersion) UnmarshalJSON(data []byte) (err error) {
// JSON has two distinct ways to represent numbers and strings.
// This means we cannot simply unmarshal to string, like with YAML.
// Unmarshalling to `any` causes Go to unmarshal numbers to float64.
// Therefore, try to unmarshal to string, and then to int, instead of using type assertions.
var unmarshalString string
if err := json.Unmarshal(data, &unmarshalString); err != nil {
var unmarshalInt int64
if err := json.Unmarshal(data, &unmarshalInt); err != nil {
return fmt.Errorf("unable to unmarshal to string or int: %w", err)
}
unmarshalString = strconv.FormatInt(unmarshalInt, 10)
}

return v.parseRawUnmarshal(unmarshalString)
func (v *AttestationVersion[T]) UnmarshalJSON(data []byte) (err error) {
return v.unmarshal(func(a any) error {
return json.Unmarshal(data, a)
})
}

func (v *AttestationVersion) parseRawUnmarshal(str string) error {
if strings.HasPrefix(str, "0") && len(str) != 1 {
return fmt.Errorf("no format with prefixed 0 (octal, hexadecimal) allowed: %s", str)
// unmarshal takes care of unmarshalling the value from YAML or JSON.
func (v *AttestationVersion[T]) unmarshal(unmarshal func(any) error) error {
// Start by trying to unmarshal to the distinct type
var distinctType T
if err := unmarshal(&distinctType); err == nil {
v.Value = distinctType
return nil
}
if strings.ToLower(str) == "latest" {

var unmarshalString string
if err := unmarshal(&unmarshalString); err != nil {
return fmt.Errorf("failed unmarshalling to %T or string: %w", distinctType, err)
}

if strings.ToLower(unmarshalString) == "latest" {
v.WantLatest = true
v.Value = placeholderVersionValue
} else {
ui, err := strconv.ParseUint(str, 10, 8)
if err != nil {
return fmt.Errorf("invalid version value: %s", str)
}
if ui > math.MaxUint8 {
return fmt.Errorf("integer value is out ouf uint8 range: %d", ui)
}
v.Value = uint8(ui)
v.Value = placeholderVersionValue[T]()
return nil
}
return nil

return fmt.Errorf("failed unmarshalling to %T or string: invalid value: %s", distinctType, unmarshalString)
}
Loading

0 comments on commit f68709d

Please sign in to comment.