Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methods to directly add Reference Values and Endorsed Values #142

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 121 additions & 21 deletions comid/comid.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,27 +243,27 @@ func (o *Comid) AddDevIdentityKey(val KeyTriple) *Comid {
}

func (o Comid) Valid() error {
if err := o.TagIdentity.Valid(); err != nil {
return fmt.Errorf("tag-identity validation failed: %w", err)
}

if o.Entities != nil {
if err := o.Entities.Valid(); err != nil {
return fmt.Errorf("entities validation failed: %w", err)
}
}

if o.LinkedTags != nil {
if err := o.LinkedTags.Valid(); err != nil {
return fmt.Errorf("linked-tags validation failed: %w", err)
}
}

if err := o.Triples.Valid(); err != nil {
return fmt.Errorf("triples validation failed: %w", err)
}

return o.Extensions.validComid(&o)
if err := o.TagIdentity.Valid(); err != nil {
return fmt.Errorf("tag-identity validation failed: %v", err) // Changed %w to %v
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

(also, remove the comments -- they don't make sense without historical context)

}

if o.Entities != nil {
if err := o.Entities.Valid(); err != nil {
return fmt.Errorf("entities validation failed: %v", err) // Changed %w to %v
}
}

if o.LinkedTags != nil {
if err := o.LinkedTags.Valid(); err != nil {
return fmt.Errorf("linked-tags validation failed: %v", err) // Changed %w to %v
}
}

if err := o.Triples.Valid(); err != nil {
return fmt.Errorf("triples validation failed: %v", err) // Changed %w to %v
}

return o.Extensions.validComid(&o)
}

// ToCBOR serializes the target Comid to CBOR
Expand Down Expand Up @@ -321,3 +321,103 @@ func (o Comid) ToJSONPretty(indent string) ([]byte, error) {

return json.MarshalIndent(&o, "", indent)
}

// AddSimpleReferenceValue adds a reference value with a single measurement
func (o *Comid) AddSimpleReferenceValue(env Environment, measurement *Measurement) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think "simple" is the right term for this. Perhaps something like AddReferenceValueFromMeasurement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not address #136, as this does not handle extensions, which is the intent of adding the helper methods.

Note that the issue says "without creating instances of measurements" -- where as this still requres a measurement instance. The reason is that extensions are registred with the collection, and are not propagated to the reference values (and then, through measurement, down to the Mval and the Flags) until the values are added to the collection, so its not possible to specify values for the extension fields until the reference value is in the collection.

The goal of #136 is to address that by adding a method that adds a reference/endorsement value from all raw inputs in asingle operation.

Another issue that, as of the latest CoRIM spec update, a reference value can contain multiple measurements, so the mothod would need to accomodate that as well....

if err := env.Valid(); err != nil {
return fmt.Errorf("invalid environment: %w", err)
}

if measurement == nil {
return fmt.Errorf("measurement cannot be nil")
}

if o.Triples.ReferenceValues == nil {
o.Triples.ReferenceValues = NewValueTriples()
}

builder := NewReferenceValueBuilder().
WithEnvironment(env).
WithMeasurement(measurement)

triple, err := builder.Build()
if err != nil {
return fmt.Errorf("building reference value: %w", err)
}

if res := o.AddReferenceValue(*triple); res == nil {
return fmt.Errorf("failed to add reference value")
}

return nil
}

func (o *Comid) AddDigestReferenceValue(env Environment, alg string, digest []byte) error {
if len(digest) == 0 {
return fmt.Errorf("digest cannot be empty")
}
hashAlg := HashAlgFromString(alg)
if !hashAlg.Valid() {
return fmt.Errorf("unrecognized algorithm %q", alg)
}
m := &Measurement{
Val: Mval{
Digests: NewDigests(),
},
}
if m.Val.Digests.AddDigest(hashAlg.ToUint64(), digest) == nil {
return fmt.Errorf("failed to create hash entry")
}
return o.AddSimpleReferenceValue(env, m)
}

// AddRawReferenceValue adds a reference value with raw measurement data
func (o *Comid) AddRawReferenceValue(env Environment, raw []byte) error {
if len(raw) == 0 {
return fmt.Errorf("raw value cannot be empty")
}

m := &Measurement{
Val: Mval{
RawValue: NewRawValue().SetBytes(raw),
},
}

return o.AddSimpleReferenceValue(env, m)
}

// AddReferenceValueDirect adds a reference value directly to the reference-triples list without creating instances for Measurement and ValueTriples.
func (o *Comid) AddReferenceValueDirect(environment Environment, measurements Measurements) *Comid {
if o != nil {
val := ValueTriple{
Environment: environment,
Measurements: measurements,
}
if o.Triples.ReferenceValues == nil {
o.Triples.ReferenceValues = NewValueTriples()
}

if o.Triples.AddReferenceValue(val) == nil {
return nil
}
}
return o
}

// AddEndorsedValueDirect adds an endorsed value directly to the endorsed-triples list without creating instances for Measurement and ValueTriples.
func (o *Comid) AddEndorsedValueDirect(environment Environment, measurements Measurements) *Comid {
if o != nil {
val := ValueTriple{
Environment: environment,
Measurements: measurements,
}
if o.Triples.EndorsedValues == nil {
o.Triples.EndorsedValues = NewValueTriples()
}

if o.Triples.AddEndorsedValue(val) == nil {
return nil
}
}
return o
}
30 changes: 30 additions & 0 deletions comid/comid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,33 @@ func Test_String2URI_nok(t *testing.T) {
_, err := String2URI(&s)
assert.EqualError(t, err, `expecting an absolute URI: "@@@" is not an absolute URI`)
}


func Test_Comid_SimpleReferenceValue(t *testing.T) {
c := NewComid()
env := Environment{
Instance: MustNewUUIDInstance(TestUUID),
}

// Test digest reference value
err := c.AddDigestReferenceValue(env, "sha-256", []byte{
0x00, 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,
})
require.NoError(t, err)

// Verify values were added
require.NotNil(t, c.Triples.ReferenceValues)
require.Len(t, c.Triples.ReferenceValues.Values, 1)

// Verify digest value
rv := c.Triples.ReferenceValues.Values[0]
require.NotNil(t, rv.Measurements.Values[0].Val.Digests)
require.Equal(t, HashAlgSHA256.ToUint64(), (*rv.Measurements.Values[0].Val.Digests)[0].HashAlgID)
}
63 changes: 31 additions & 32 deletions comid/digests.go
Original file line number Diff line number Diff line change
@@ -1,53 +1,52 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package comid

import (
"fmt"

"github.com/veraison/swid"
"fmt"
"github.com/veraison/swid"
)

// Digests is an alias for an array of SWID HashEntry
// Digests is an array of SWID HashEntry
type Digests []swid.HashEntry

// NewDigests instantiates an empty array of Digests
func NewDigests() *Digests {
return new(Digests)
return new(Digests)
}

// AddDigest create a new digest from the supplied arguments and appends it to
// the (already instantiated) Digests target. The method is a no-op if it is
// invoked on a nil target and will refuse to add inconsistent algo/value
// combinations.
// AddDigest create a new digest from the supplied arguments and appends it to the (already instantiated) Digests target.
// The method is a no-op if it is invoked on a nil target and will refuse to add inconsistent algo/value combinations.
func (o *Digests) AddDigest(algID uint64, value []byte) *Digests {
if o != nil {
he := NewHashEntry(algID, value)
if he == nil {
return nil
}
*o = append(*o, *he)
}
return o
if o != nil {
he := NewHashEntry(algID, value)
if he == nil {
return nil
}
*o = append(*o, *he)
}
return o
}

func (o Digests) Valid() error {
for i, m := range o {
if err := swid.ValidHashEntry(m.HashAlgID, m.HashValue); err != nil {
return fmt.Errorf("digest at index %d: %w", i, err)
}
}
return nil
if len(o) == 0 {
return fmt.Errorf("digests must not be empty")
}

for i, m := range o {
if err := swid.ValidHashEntry(m.HashAlgID, m.HashValue); err != nil {
return fmt.Errorf("digest at index %d: %w", i, err)
}
}
return nil
}


func NewHashEntry(algID uint64, value []byte) *swid.HashEntry {
var he swid.HashEntry
var he swid.HashEntry

err := he.Set(algID, value)
if err != nil {
return nil
}
err := he.Set(algID, value)
if err != nil {
return nil
}

return &he
return &he
}
77 changes: 77 additions & 0 deletions comid/hashalg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package comid

import (
"fmt"
"strings"
"encoding/json"
)

type HashAlg uint64

const (
HashAlgSHA256 HashAlg = 1
HashAlgSHA384 HashAlg = 2
HashAlgSHA512 HashAlg = 3
)

func (h HashAlg) Valid() bool {
return h >= HashAlgSHA256 && h <= HashAlgSHA512
}

func HashAlgFromString(s string) HashAlg {
switch strings.ToLower(s) {
case "sha-256":
return HashAlgSHA256
case "sha-384":
return HashAlgSHA384
case "sha-512":
return HashAlgSHA512
default:
return 0
}
}

func (h HashAlg) String() string {
switch h {
case HashAlgSHA256:
return "sha-256"
case HashAlgSHA384:
return "sha-384"
case HashAlgSHA512:
return "sha-512"
default:
return fmt.Sprintf("unknown(%d)", h)
}
}

func (h HashAlg) MarshalJSON() ([]byte, error) {
return json.Marshal(h.String())
}
func (h *HashAlg) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
*h = HashAlgFromString(s)
if !h.Valid() {
return fmt.Errorf("invalid hash algorithm: %s", s)
}
return nil
}

// ToUint64 returns 0 if invalid, otherwise the numeric value.
func (h HashAlg) ToUint64() uint64 {
if !h.Valid() {
return 0
}
return uint64(h)
}

// HashAlgFromUint64 returns 0 if v is invalid, otherwise the matching HashAlg.
func HashAlgFromUint64(v uint64) HashAlg {
h := HashAlg(v)
if !h.Valid() {
return 0
}
return h
}
Loading