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:
Daniel Weiße 2023-03-08 14:13:57 +01:00 committed by Malte Poll
parent d104af6e51
commit dd2da25ebe
53 changed files with 808 additions and 229 deletions

View file

@ -43,6 +43,12 @@ const (
// The value used to extend is derived from Constellation's master key.
// TODO: move to stable, non-debug PCR before use.
PCRIndexOwnerID = tpmutil.Handle(16)
// TDXIndexClusterID is the measurement used to mark the node as initialized.
// The value is the index of the RTMR + 1, since index 0 of the TDX measurements is reserved for MRTD.
TDXIndexClusterID = RTMRIndexClusterID + 1
// RTMRIndexClusterID is the RTMR we extend to mark the node as initialized.
RTMRIndexClusterID = 2
)
// M are Platform Configuration Register (PCR) values that make up the Measurements.
@ -128,7 +134,7 @@ func (m *M) EqualTo(other M) bool {
}
for k, v := range *m {
otherExpected := other[k].Expected
if !bytes.Equal(v.Expected[:], otherExpected[:]) {
if !bytes.Equal(v.Expected, otherExpected) {
return false
}
if v.ValidationOpt != other[k].ValidationOpt {
@ -177,10 +183,45 @@ func (m *M) SetEnforced(enforced []uint32) error {
return nil
}
// UnmarshalJSON unmarshals measurements from json.
// This function enforces all measurements to be of equal length.
func (m *M) UnmarshalJSON(b []byte) error {
newM := make(map[uint32]Measurement)
if err := json.Unmarshal(b, &newM); err != nil {
return err
}
// check if all measurements are of equal length
if err := checkLength(newM); err != nil {
return err
}
*m = newM
return nil
}
// UnmarshalYAML unmarshals measurements from yaml.
// This function enforces all measurements to be of equal length.
func (m *M) UnmarshalYAML(unmarshal func(any) error) error {
newM := make(map[uint32]Measurement)
if err := unmarshal(&newM); err != nil {
return err
}
// check if all measurements are of equal length
if err := checkLength(newM); err != nil {
return err
}
*m = newM
return nil
}
// Measurement wraps expected PCR value and whether it is enforced.
type Measurement struct {
// Expected measurement value.
Expected [32]byte `json:"expected" yaml:"expected"`
// 32 bytes for vTPM attestation, 48 for TDX.
Expected []byte `json:"expected" yaml:"expected"`
// ValidationOpt indicates how measurement mismatches should be handled.
ValidationOpt MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`
}
@ -269,11 +310,11 @@ func (m *Measurement) unmarshal(eM encodedMeasurement) error {
}
}
if len(expected) != 32 {
if len(expected) != 32 && len(expected) != 48 {
return fmt.Errorf("invalid measurement: invalid length: %d", len(expected))
}
m.Expected = *(*[32]byte)(expected)
m.Expected = expected
m.ValidationOpt = eM.WarnOnly
return nil
@ -282,7 +323,7 @@ func (m *Measurement) unmarshal(eM encodedMeasurement) error {
// WithAllBytes returns a measurement value where all 32 bytes are set to b.
func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement {
return Measurement{
Expected: *(*[32]byte)(bytes.Repeat([]byte{b}, 32)),
Expected: bytes.Repeat([]byte{b}, 32),
ValidationOpt: validationOpt,
}
}
@ -290,7 +331,7 @@ func WithAllBytes(b byte, validationOpt MeasurementValidationOption) Measurement
// PlaceHolderMeasurement returns a measurement with placeholder values for Expected.
func PlaceHolderMeasurement() Measurement {
return Measurement{
Expected: *(*[32]byte)(bytes.Repeat([]byte{0x12, 0x34}, 16)),
Expected: bytes.Repeat([]byte{0x12, 0x34}, 16),
ValidationOpt: Enforce,
}
}
@ -316,6 +357,18 @@ func getFromURL(ctx context.Context, client *http.Client, sourceURL *url.URL) ([
return content, nil
}
func checkLength(m map[uint32]Measurement) error {
var length int
for idx, measurement := range m {
if length == 0 {
length = len(measurement.Expected)
} else if len(measurement.Expected) != length {
return fmt.Errorf("inconsistent measurement length: index %d: expected %d, got %d", idx, length, len(measurement.Expected))
}
}
return nil
}
type encodedMeasurement struct {
Expected string `json:"expected" yaml:"expected"`
WarnOnly MeasurementValidationOption `json:"warnOnly" yaml:"warnOnly"`