Skip to content

Commit

Permalink
comid: replace opflag with FlagsMap
Browse files Browse the repository at this point in the history
Replace a single uint8 bitfield used to keep track of op flags with a
flags map that allows tristate flags (true, false, and unset). This
reflects flags representation in

https://www.ietf.org/archive/id/draft-ietf-rats-corim-02.html

Signed-off-by: Sergei Trofimov <[email protected]>
  • Loading branch information
setrofim committed Nov 14, 2023
1 parent 1bdfefa commit 0fe0afb
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 218 deletions.
177 changes: 177 additions & 0 deletions comid/flagsmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright 2023 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package comid

var True = true
var False = false

// Flag indicates whether a particular operational mode is active within the
// measured environment.
type Flag int

const (
FlagIsConfigured Flag = iota
FlagIsSecure
FlagIsRecovery
FlagIsDebug
FlagIsReplayProtected
FlagIsIntegrityProtected
FlagIsRuntimeMeasured
FlagIsImmutable
FlagIsTcb
)

// FlagsMap describes a number of boolean operational modes. If a value is nil,
// then the operational mode is unknown.
type FlagsMap struct {
// IsConfigured indicates whether the measured environment is fully
// configured for normal operation.
IsConfigured *bool `cbor:"0,keyasint,omitempty" json:"is-configured,omitempty"`
// IsSecure indicates whether the measured environment's configurable
// security settings are fully enabled.
IsSecure *bool `cbor:"1,keyasint,omitempty" json:"is-secure,omitempty"`
// IsRecovery indicates whether the measured environment is in recovery
// mode.
IsRecovery *bool `cbor:"2,keyasint,omitempty" json:"is-recovery,omitempty"`
// IsDebug indicates whether the measured environment is in a debug
// enabled mode.
IsDebug *bool `cbor:"3,keyasint,omitempty" json:"is-debug,omitempty"`
// IsReplayProtected indicates whether the measured environment is
// protected from replay by a previous image that differs from the
// current image.
IsReplayProtected *bool `cbor:"4,keyasint,omitempty" json:"is-replay-protected,omitempty"`
// IsIntegrityProtected indicates whether the measured environment is
// protected from unauthorized update.
IsIntegrityProtected *bool `cbor:"5,keyasint,omitempty" json:"is-integrity-protected,omitempty"`
// IsRuntimeMeasured indicates whether the measured environment is
// measured after being loaded into memory.
IsRuntimeMeasured *bool `cbor:"6,keyasint,omitempty" json:"is-runtime-meas,omitempty"`
// IsImmutable indicates whether the measured environment is immutable.
IsImmutable *bool `cbor:"7,keyasint,omitempty" json:"is-immutable,omitempty"`
// IsTcb indicates whether the measured environment is a trusted
// computing base.
IsTcb *bool `cbor:"8,keyasint,omitempty" json:"is-tcb,omitempty"`
}

func NewFlagsMap() *FlagsMap {
return &FlagsMap{}
}

func (o *FlagsMap) AnySet() bool {
if o.IsConfigured != nil || o.IsSecure != nil || o.IsRecovery != nil || o.IsDebug != nil ||
o.IsReplayProtected != nil || o.IsIntegrityProtected != nil ||
o.IsRuntimeMeasured != nil || o.IsImmutable != nil || o.IsTcb != nil {
return true
}

return false
}

func (o *FlagsMap) SetTrue(flags ...Flag) {
for _, flag := range flags {
switch flag {
case FlagIsConfigured:
o.IsConfigured = &True
case FlagIsSecure:
o.IsSecure = &True
case FlagIsRecovery:
o.IsRecovery = &True
case FlagIsDebug:
o.IsDebug = &True
case FlagIsReplayProtected:
o.IsReplayProtected = &True
case FlagIsIntegrityProtected:
o.IsIntegrityProtected = &True
case FlagIsRuntimeMeasured:
o.IsRuntimeMeasured = &True
case FlagIsImmutable:
o.IsImmutable = &True
case FlagIsTcb:
o.IsTcb = &True
default:
}
}
}

func (o *FlagsMap) SetFalse(flags ...Flag) {
for _, flag := range flags {
switch flag {
case FlagIsConfigured:
o.IsConfigured = &False
case FlagIsSecure:
o.IsSecure = &False
case FlagIsRecovery:
o.IsRecovery = &False
case FlagIsDebug:
o.IsDebug = &False
case FlagIsReplayProtected:
o.IsReplayProtected = &False
case FlagIsIntegrityProtected:
o.IsIntegrityProtected = &False
case FlagIsRuntimeMeasured:
o.IsRuntimeMeasured = &False
case FlagIsImmutable:
o.IsImmutable = &False
case FlagIsTcb:
o.IsTcb = &False
default:
}
}
}

func (o *FlagsMap) Clear(flags ...Flag) {
for _, flag := range flags {
switch flag {
case FlagIsConfigured:
o.IsConfigured = nil
case FlagIsSecure:
o.IsSecure = nil
case FlagIsRecovery:
o.IsRecovery = nil
case FlagIsDebug:
o.IsDebug = nil
case FlagIsReplayProtected:
o.IsReplayProtected = nil
case FlagIsIntegrityProtected:
o.IsIntegrityProtected = nil
case FlagIsRuntimeMeasured:
o.IsRuntimeMeasured = nil
case FlagIsImmutable:
o.IsImmutable = nil
case FlagIsTcb:
o.IsTcb = nil
default:
}
}
}

func (o *FlagsMap) Get(flag Flag) *bool {
switch flag {
case FlagIsConfigured:
return o.IsConfigured
case FlagIsSecure:
return o.IsSecure
case FlagIsRecovery:
return o.IsRecovery
case FlagIsDebug:
return o.IsDebug
case FlagIsReplayProtected:
return o.IsReplayProtected
case FlagIsIntegrityProtected:
return o.IsIntegrityProtected
case FlagIsRuntimeMeasured:
return o.IsRuntimeMeasured
case FlagIsImmutable:
return o.IsImmutable
case FlagIsTcb:
return o.IsTcb
default:
return nil
}
}

// Valid returns an error if the FlagsMap is invalid.
func (o FlagsMap) Valid() error {
return nil
}
41 changes: 41 additions & 0 deletions comid/flagsmap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package comid

import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_FlagsMap(t *testing.T) {
fm := NewFlagsMap()
assert.False(t, fm.AnySet())

for _, flag := range []Flag{
FlagIsConfigured,
FlagIsSecure,
FlagIsRecovery,
FlagIsDebug,
FlagIsReplayProtected,
FlagIsIntegrityProtected,
FlagIsRuntimeMeasured,
FlagIsImmutable,
FlagIsTcb,
} {
fm.SetTrue(flag)
assert.True(t, fm.AnySet())
assert.Equal(t, true, *fm.Get(flag))

fm.SetFalse(flag)
assert.True(t, fm.AnySet())
assert.Equal(t, false, *fm.Get(flag))

fm.Clear(flag)
assert.False(t, fm.AnySet())
assert.Equal(t, (*bool)(nil), fm.Get(flag))
}

fm.SetTrue(Flag(-1))
fm.SetFalse(Flag(-1))
assert.False(t, fm.AnySet())
assert.Equal(t, (*bool)(nil), fm.Get(Flag(-1)))
}
84 changes: 72 additions & 12 deletions comid/measurement.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"fmt"
"net"

"github.com/veraison/corim/encoding"
"github.com/veraison/corim/extensions"
"github.com/veraison/eat"
"github.com/veraison/swid"
)
Expand All @@ -16,8 +18,9 @@ const MaxUint64 = ^uint64(0)

// Measurement stores a measurement-map with CBOR and JSON serializations.
type Measurement struct {
Key *Mkey `cbor:"0,keyasint,omitempty" json:"key,omitempty"`
Val Mval `cbor:"1,keyasint" json:"value"`
Key *Mkey `cbor:"0,keyasint,omitempty" json:"key,omitempty"`
Val Mval `cbor:"1,keyasint" json:"value"`
AuthorizedBy *CryptoKey `cbor:"2,keyasint,omitempty" json:"authorized-by,omitempty"`
}

// Mkey stores a $measured-element-type-choice.
Expand Down Expand Up @@ -212,21 +215,43 @@ type Mval struct {
Ver *Version `cbor:"0,keyasint,omitempty" json:"version,omitempty"`
SVN *SVN `cbor:"1,keyasint,omitempty" json:"svn,omitempty"`
Digests *Digests `cbor:"2,keyasint,omitempty" json:"digests,omitempty"`
OpFlags *OpFlags `cbor:"3,keyasint,omitempty" json:"op-flags,omitempty"`
Flags *FlagsMap `cbor:"3,keyasint,omitempty" json:"flags,omitempty"`
RawValue *RawValue `cbor:"4,keyasint,omitempty" json:"raw-value,omitempty"`
RawValueMask *[]byte `cbor:"5,keyasint,omitempty" json:"raw-value-mask,omitempty"`
MACAddr *MACaddr `cbor:"6,keyasint,omitempty" json:"mac-addr,omitempty"`
IPAddr *net.IP `cbor:"7,keyasint,omitempty" json:"ip-addr,omitempty"`
SerialNumber *string `cbor:"8,keyasint,omitempty" json:"serial-number,omitempty"`
UEID *eat.UEID `cbor:"9,keyasint,omitempty" json:"ueid,omitempty"`
UUID *UUID `cbor:"10,keyasint,omitempty" json:"uuid,omitempty"`

Extensions
}

// RegisterExtensions registers a struct as a collections of extensions
func (o *Mval) RegisterExtensions(exts extensions.IExtensionsValue) {
o.Extensions.Register(exts)
}

// GetExtensions returns pervisouosly registered extension
func (o *Mval) GetExtensions() extensions.IExtensionsValue {
return o.Extensions.IExtensionsValue
}

// UnmarshalCBOR deserializes from CBOR
func (o *Mval) UnmarshalCBOR(data []byte) error {
return encoding.PopulateStructFromCBOR(dm, data, o)
}

// MarshalCBOR serializes to CBOR
func (o *Mval) MarshalCBOR() ([]byte, error) {
return encoding.SerializeStructToCBOR(em, o)
}

func (o Mval) Valid() error {
if o.Ver == nil &&
o.SVN == nil &&
o.Digests == nil &&
o.OpFlags == nil &&
o.Flags == nil &&
o.RawValue == nil &&
o.RawValueMask == nil &&
o.MACAddr == nil &&
Expand All @@ -249,8 +274,8 @@ func (o Mval) Valid() error {
}
}

if o.OpFlags != nil {
if err := o.OpFlags.Valid(); err != nil {
if o.Flags != nil {
if err := o.Flags.Valid(); err != nil {
return err
}
}
Expand All @@ -259,7 +284,7 @@ func (o Mval) Valid() error {

// TODO(tho) MAC addr & friends (see https://github.com/veraison/corim/issues/18)

return nil
return o.Extensions.ValidMval(&o)
}

// Version stores a version-map with JSON and CBOR serializations.
Expand Down Expand Up @@ -450,16 +475,51 @@ func (o *Measurement) AddDigest(algID uint64, digest []byte) *Measurement {
}
o.Val.Digests = ds
}

return o
}

// SetOpFlags sets the supplied operational flags in the measurement-values-map
// of the target measurement
func (o *Measurement) SetOpFlags(flags ...OpFlags) *Measurement {
// SetFlagsTrue sets the supplied operational flags to true in the
// measurement-values-map of the target measurement
func (o *Measurement) SetFlagsTrue(flags ...Flag) *Measurement {
if o != nil {
if o.Val.Flags == nil {
o.Val.Flags = NewFlagsMap()
}
o.Val.Flags.SetTrue(flags...)
}

return o
}

// SetFlagsFalse sets the supplied operational flags to true in the
// measurement-values-map of the target measurement
func (o *Measurement) SetFlagsFalse(flags ...Flag) *Measurement {
if o != nil {
o.Val.OpFlags = NewOpFlags()
o.Val.OpFlags.SetOpFlags(flags...)
if o.Val.Flags == nil {
o.Val.Flags = NewFlagsMap()
}
o.Val.Flags.SetFalse(flags...)
}

return o
}

// ClearFlags clears the supplied operational flags in the
// measurement-values-map of the target measurement
func (o *Measurement) ClearFlags(flags ...Flag) *Measurement {
if o != nil {
if o.Val.Flags == nil {
return o
}

o.Val.Flags.Clear(flags...)

if !o.Val.Flags.AnySet() {
o.Val.Flags = nil
}
}

return o
}

Expand Down
Loading

0 comments on commit 0fe0afb

Please sign in to comment.