From 578b61e89e05fd50dabb2f411f81ca18fd28d216 Mon Sep 17 00:00:00 2001 From: Yogesh Deshpande Date: Wed, 24 Nov 2021 07:10:39 -0500 Subject: [PATCH] Set MKey as uint --- comid/example_test.go | 28 +++++ comid/measurement.go | 60 +++++++++- comid/measurement_test.go | 238 ++++++++++++++++++++++++++++++++++++++ comid/test_vars.go | 17 +-- 4 files changed, 332 insertions(+), 11 deletions(-) diff --git a/comid/example_test.go b/comid/example_test.go index c979671e..bd3197f9 100644 --- a/comid/example_test.go +++ b/comid/example_test.go @@ -588,3 +588,31 @@ func Example_decode_CBOR_4() { // Output: OK } + +func Example_decode_CBOR_5() { + // Taken from https://github.com/ietf-corim-cddl/blob/main/examples/comid-3.diag + in := []byte{ + 0xa3, 0x01, 0xa1, 0x00, 0x78, 0x20, 0x6d, 0x79, 0x2d, 0x6e, 0x73, 0x3a, + 0x61, 0x63, 0x6d, 0x65, 0x2d, 0x72, 0x6f, 0x61, 0x64, 0x72, 0x75, 0x6e, + 0x6e, 0x65, 0x72, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x02, 0x81, 0xa3, 0x00, 0x69, 0x41, 0x43, 0x4d, 0x45, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x01, 0xd8, 0x20, 0x74, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x02, 0x83, 0x01, 0x00, 0x02, 0x04, 0xa1, 0x00, + 0x81, 0x82, 0xa1, 0x00, 0xa3, 0x00, 0xd8, 0x6f, 0x44, 0x55, 0x02, 0xc0, + 0x00, 0x01, 0x69, 0x41, 0x43, 0x4d, 0x45, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x02, 0x78, 0x18, 0x41, 0x43, 0x4d, 0x45, 0x20, 0x52, 0x6f, 0x61, 0x64, + 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x20, 0x46, 0x69, 0x72, 0x6d, 0x77, + 0x61, 0x72, 0x65, 0x81, 0xa2, 0x00, 0x19, 0x02, 0xbc, 0x01, 0xa1, 0x02, + 0x81, 0x82, 0x06, 0x44, 0xab, 0xcd, 0xef, 0x00, + } + comid := Comid{} + err := comid.FromCBOR(in) + if err != nil { + fmt.Printf("FAIL: %v", err) + } else { + fmt.Println("OK") + } + + // Output: OK +} diff --git a/comid/measurement.go b/comid/measurement.go index 5f741487..01df9f5e 100644 --- a/comid/measurement.go +++ b/comid/measurement.go @@ -12,6 +12,8 @@ import ( "github.com/veraison/swid" ) +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"` @@ -19,7 +21,8 @@ type Measurement struct { } // Mkey stores a $measured-element-type-choice. -// The supported types are UUID and PSA refval-id. +// The supported types are UUID, PSA refval-id and unsigned integer +// TO DO Add tagged OID: see https://github.com/veraison/corim/issues/35 type Mkey struct { val interface{} } @@ -37,8 +40,13 @@ func (o Mkey) Valid() error { return nil case TaggedPSARefValID: return PSARefValID(t).Valid() + case uint64: + if o.val == nil { + return fmt.Errorf("empty uint Mkey") + } + return nil default: - return fmt.Errorf("unknown measurement key type %T", t) + return fmt.Errorf("unknown measurement key type: %T", t) } } @@ -51,6 +59,15 @@ func (o Mkey) GetPSARefValID() (PSARefValID, error) { } } +func (o Mkey) GetKeyUint() (uint64, error) { + switch t := o.val.(type) { + case uint64: + return t, nil + default: + return MaxUint64, fmt.Errorf("measurement-key type is: %T", t) + } +} + // UnmarshalJSON deserializes the type'n'value JSON object into the target Mkey func (o *Mkey) UnmarshalJSON(data []byte) error { var v tnv @@ -84,6 +101,15 @@ func (o *Mkey) UnmarshalJSON(data []byte) error { ) } o.val = TaggedPSARefValID(x) + case "uint": + var x uint64 + if err := json.Unmarshal(v.Value, &x); err != nil { + return fmt.Errorf( + "cannot unmarshal $measured-element-type-choice of type uint: %w", + err, + ) + } + o.val = x default: return fmt.Errorf("unknown type %s for $measured-element-type-choice", v.Type) } @@ -92,7 +118,7 @@ func (o *Mkey) UnmarshalJSON(data []byte) error { } // MarshalJSON serializes the target Mkey into the type'n'value JSON object -// uuid, psa.refval-id +// Supported types are: uuid, psa.refval-id and unsigned integer func (o Mkey) MarshalJSON() ([]byte, error) { var ( v tnv @@ -114,6 +140,13 @@ func (o Mkey) MarshalJSON() ([]byte, error) { return nil, err } v = tnv{Type: "psa.refval-id", Value: b} + case uint64: + b, err = json.Marshal(t) + if err != nil { + return nil, err + } + v = tnv{Type: "uint", Value: b} + default: return nil, fmt.Errorf("unknown type %T for mkey", t) } @@ -122,6 +155,9 @@ func (o Mkey) MarshalJSON() ([]byte, error) { } func (o Mkey) MarshalCBOR() ([]byte, error) { + if err := o.Valid(); err != nil { + return nil, err + } return em.Marshal(o.val) } @@ -255,6 +291,17 @@ func (o *Measurement) SetKeyUUID(u UUID) *Measurement { return o } +// SetKeyUint sets the key of the target measurement-map to the supplied +// unsigned integer +func (o *Measurement) SetKeyUint(u uint64) *Measurement { + if o != nil { + o.Key = &Mkey{ + val: u, + } + } + return o +} + // NewPSAMeasurement instantiates a new measurement-map with the key set to the // supplied PSA refval-id func NewPSAMeasurement(psaRefValID PSARefValID) *Measurement { @@ -269,6 +316,13 @@ func NewUUIDMeasurement(uuid UUID) *Measurement { return m.SetKeyUUID(uuid) } +// NewUintMeasurement instantiates a new measurement-map with the key set to the +// supplied Uint +func NewUintMeasurement(mkey uint64) *Measurement { + m := &Measurement{} + return m.SetKeyUint(mkey) +} + func (o *Measurement) SetVersion(ver string, scheme uint64) *Measurement { if o != nil { v := NewVersion().SetVersion(ver).SetScheme(scheme) diff --git a/comid/measurement_test.go b/comid/measurement_test.go index 11ecc672..30d0dede 100644 --- a/comid/measurement_test.go +++ b/comid/measurement_test.go @@ -4,6 +4,7 @@ package comid import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -26,6 +27,14 @@ func TestMeasurement_NewUUIDMeasurement_empty_uuid(t *testing.T) { assert.Nil(t, tv) } +func TestMeasurement_NewUIntMeasurement(t *testing.T) { + var TestUint uint64 = 35 + + tv := NewUintMeasurement(TestUint) + + assert.NotNil(t, tv) +} + func TestMeasurement_NewPSAMeasurement_empty(t *testing.T) { emptyPSARefValID := PSARefValID{} @@ -112,3 +121,232 @@ func TestMeasurement_NewUUIDMeasurement_bad_uuid(t *testing.T) { assert.Nil(t, tv.SetUUID(nonRFC4122UUID)) } + +var ( + testMKeyUintMin uint64 = 0 + testMKeyUintMax uint64 = ^uint64(0) +) + +func TestMkey_Valid_no_value(t *testing.T) { + mkey := &Mkey{} + expectedErr := "unknown measurement key type: " + err := mkey.Valid() + assert.EqualError(t, err, expectedErr) +} + +func TestMeasurement_MarshalCBOR_uint_mkey_ok(t *testing.T) { + tvs := []struct { + mkey uint64 + expected []byte + }{ + { + mkey: testMKeyUintMin, + expected: MustHexDecode(t, "00"), + }, + { + mkey: TestMKey, + expected: MustHexDecode(t, "1902BC"), + }, + { + mkey: testMKeyUintMax, + expected: MustHexDecode(t, "1BFFFFFFFFFFFFFFFF"), + }, + } + + for _, tv := range tvs { + meas := NewUintMeasurement(tv.mkey) + require.NotNil(t, meas) + + actual, err := meas.Key.MarshalCBOR() + assert.Nil(t, err) + assert.Equal(t, tv.expected, actual) + fmt.Printf("CBOR: %x\n", actual) + } +} +func TestMkey_MarshalCBOR_uint_not_ok(t *testing.T) { + tvs := []struct { + input interface{} + expected string + }{ + { + input: 123.456, + expected: "unknown measurement key type: float64", + }, + { + input: "sample", + expected: "unknown measurement key type: string", + }, + } + + for _, tv := range tvs { + mkey := &Mkey{tv.input} + _, err := mkey.MarshalCBOR() + + assert.EqualError(t, err, tv.expected) + } +} + +func TestMkey_UnmarshalCBOR_uint_ok(t *testing.T) { + tvs := []struct { + mkey []byte + expected uint64 + }{ + { + mkey: MustHexDecode(t, "00"), + expected: testMKeyUintMin, + }, + { + mkey: MustHexDecode(t, "1902BC"), + expected: TestMKey, + }, + { + mkey: MustHexDecode(t, "1BFFFFFFFFFFFFFFFF"), + expected: testMKeyUintMax, + }, + } + + for _, tv := range tvs { + mKey := &Mkey{} + + err := mKey.UnmarshalCBOR(tv.mkey) + assert.Nil(t, err) + actual, err := mKey.GetKeyUint() + assert.Nil(t, err) + assert.Equal(t, tv.expected, actual) + } +} + +func TestMkey_UnmarshalCBOR_uint_not_ok(t *testing.T) { + tvs := []struct { + input []byte + expected string + }{ + { + input: []byte{0xAB, 0xCD}, + expected: "unexpected EOF", + }, + { + input: []byte{0xCC, 0xDD, 0xFF}, + expected: "cbor: invalid additional information 29 for type tag", + }, + } + + for _, tv := range tvs { + mKey := &Mkey{} + + err := mKey.UnmarshalCBOR(tv.input) + + assert.EqualError(t, err, tv.expected) + } +} + +func TestMkey_MarshalJSON_uint_ok(t *testing.T) { + tvs := []struct { + mkey uint64 + expected []byte + }{ + { + mkey: testMKeyUintMin, + expected: []byte(`{"type":"uint","value":0}`), + }, + { + mkey: TestMKey, + expected: []byte(`{"type":"uint","value":700}`), + }, + { + mkey: testMKeyUintMax, + expected: []byte(`{"type":"uint","value":18446744073709551615}`), + }, + } + + for _, tv := range tvs { + + meas := NewUintMeasurement(tv.mkey) + require.NotNil(t, meas) + + actual, err := meas.Key.MarshalJSON() + assert.Nil(t, err) + assert.Equal(t, tv.expected, actual) + + fmt.Printf("JSON: %x\n", actual) + } +} + +func TestMkey_MarshalJSON_uint_not_ok(t *testing.T) { + tvs := []struct { + input interface{} + expected string + }{ + { + input: 123.456, + expected: "unknown type float64 for mkey", + }, + { + input: "sample", + expected: "unknown type string for mkey", + }, + } + + for _, tv := range tvs { + + mkey := &Mkey{tv.input} + + _, err := mkey.MarshalJSON() + + assert.EqualError(t, err, tv.expected) + } +} + +func TestMkey_UnmarshalJSON_uint_ok(t *testing.T) { + tvs := []struct { + input []byte + expected uint64 + }{ + { + input: []byte(`{"type":"uint","value":0}`), + expected: testMKeyUintMin, + }, + { + input: []byte(`{"type":"uint","value":700}`), + expected: TestMKey, + }, + { + input: []byte(`{"type":"uint","value":18446744073709551615}`), + expected: testMKeyUintMax, + }, + } + + for _, tv := range tvs { + mKey := &Mkey{} + + err := mKey.UnmarshalJSON(tv.input) + assert.Nil(t, err) + actual, err := mKey.GetKeyUint() + assert.Nil(t, err) + assert.Equal(t, tv.expected, actual) + } +} + +func TestMkey_UnmarshalJSON_uint_notok(t *testing.T) { + tvs := []struct { + input []byte + expected string + }{ + { + input: []byte(`{"type":"uint","value":"abcdefg"}`), + expected: "cannot unmarshal $measured-element-type-choice of type uint: json: cannot unmarshal string into Go value of type uint64", + }, + { + input: []byte(`{"type":"uint","value":123.456}`), + expected: "cannot unmarshal $measured-element-type-choice of type uint: json: cannot unmarshal number 123.456 into Go value of type uint64", + }, + } + + for _, tv := range tvs { + mKey := &Mkey{} + + err := mKey.UnmarshalJSON(tv.input) + + assert.EqualError(t, err, tv.expected) + } +} diff --git a/comid/test_vars.go b/comid/test_vars.go index 83aa941a..7ddfafea 100644 --- a/comid/test_vars.go +++ b/comid/test_vars.go @@ -23,14 +23,15 @@ var ( 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x64, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, }) - TestOID = "2.5.2.8192" - TestRegID = "https://acme.example" - TestMACaddr, _ = net.ParseMAC("02:00:5e:10:00:00:00:01") - TestIPaddr = net.ParseIP("2001:db8::68") - TestUEIDString = "02deadbeefdead" - TestUEID = eat.UEID(MustHexDecode(nil, TestUEIDString)) - TestSignerID = MustHexDecode(nil, "acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b") - TestTagID = "urn:example:veraison" + TestOID = "2.5.2.8192" + TestRegID = "https://acme.example" + TestMACaddr, _ = net.ParseMAC("02:00:5e:10:00:00:00:01") + TestIPaddr = net.ParseIP("2001:db8::68") + TestUEIDString = "02deadbeefdead" + TestUEID = eat.UEID(MustHexDecode(nil, TestUEIDString)) + TestSignerID = MustHexDecode(nil, "acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b") + TestTagID = "urn:example:veraison" + TestMKey uint64 = 700 ) func MustHexDecode(t *testing.T, s string) []byte {