diff --git a/comid/example_test.go b/comid/example_test.go index e807be6..85775d3 100644 --- a/comid/example_test.go +++ b/comid/example_test.go @@ -109,8 +109,8 @@ func Example_encode() { } // Output: - //a50065656e2d474201a10078206d792d6e733a61636d652d726f616472756e6e65722d737570706c656d656e740282a3006941434d45204c74642e01d8207468747470733a2f2f61636d652e6578616d706c6502820100a20069454d4341204c74642e0281020382a200781a6d792d6e733a61636d652d726f616472756e6e65722d626173650100a20078196d792d6e733a61636d652d726f616472756e6e65722d6f6c64010104a4008182a300a500d86f445502c000016941434d45204c74642e026a526f616452756e6e65720300040101d902264702deadbeefdead02d8255031fb5abf023e4992aa4e95f9c1503bfa81a200d8255031fb5abf023e4992aa4e95f9c1503bfa01aa01d90228020282820644abcdef00820644ffffffff03a201f403f504d9023044010203040544ffffffff064802005e1000000001075020010db8000000000000000000000068086c43303258373056484a484435094702deadbeefdead0a5031fb5abf023e4992aa4e95f9c1503bfa018182a300a500d8255031fb5abf023e4992aa4e95f9c1503bfa016941434d45204c74642e026a526f616452756e6e65720300040101d902264702deadbeefdead02d8255031fb5abf023e4992aa4e95f9c1503bfa81a200d8255031fb5abf023e4992aa4e95f9c1503bfa01aa01d90229020282820644abcdef00820644ffffffff03a300f401f403f504d9023044010203040544ffffffff064802005e1000000001075020010db8000000000000000000000068086c43303258373056484a484435094702deadbeefdead0a5031fb5abf023e4992aa4e95f9c1503bfa028182a101d902264702deadbeefdead81d9022a78b12d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741455731427671462b2f727938425761375a454d553178595948455138420a6c4c54344d46484f614f2b4943547449767245654570722f7366544150363648326843486462354845584b74524b6f6436514c634f4c504131513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d038182a101d8255031fb5abf023e4992aa4e95f9c1503bfa81d9022a78b12d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741455731427671462b2f727938425761375a454d553178595948455138420a6c4c54344d46484f614f2b4943547449767245654570722f7366544150363648326843486462354845584b74524b6f6436514c634f4c504131513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d - //{"lang":"en-GB","tag-identity":{"id":"my-ns:acme-roadrunner-supplement"},"entities":[{"name":"ACME Ltd.","regid":"https://acme.example","roles":["creator","tagCreator"]},{"name":"EMCA Ltd.","roles":["maintainer"]}],"linked-tags":[{"target":"my-ns:acme-roadrunner-base","rel":"supplements"},{"target":"my-ns:acme-roadrunner-old","rel":"replaces"}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.5.2.8192"},"vendor":"ACME Ltd.","model":"RoadRunner","layer":0,"index":1},"instance":{"type":"ueid","value":"At6tvu/erQ=="},"group":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}},"measurements":[{"key":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"},"value":{"svn":{"type":"exact-value","value":2},"digests":["sha-256-32;q83vAA==","sha-256-32;/////w=="],"flags":{"is-secure":false,"is-debug":true},"raw-value":{"type":"bytes","value":"AQIDBA=="},"raw-value-mask":"/////w==","mac-addr":"02:00:5e:10:00:00:00:01","ip-addr":"2001:db8::68","serial-number":"C02X70VHJHD5","ueid":"At6tvu/erQ==","uuid":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}}]}],"endorsed-values":[{"environment":{"class":{"id":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"},"vendor":"ACME Ltd.","model":"RoadRunner","layer":0,"index":1},"instance":{"type":"ueid","value":"At6tvu/erQ=="},"group":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}},"measurements":[{"key":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"},"value":{"svn":{"type":"min-value","value":2},"digests":["sha-256-32;q83vAA==","sha-256-32;/////w=="],"flags":{"is-configured":false,"is-secure":false,"is-debug":true},"raw-value":{"type":"bytes","value":"AQIDBA=="},"raw-value-mask":"/////w==","mac-addr":"02:00:5e:10:00:00:00:01","ip-addr":"2001:db8::68","serial-number":"C02X70VHJHD5","ueid":"At6tvu/erQ==","uuid":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}}]}],"dev-identity-keys":[{"environment":{"instance":{"type":"ueid","value":"At6tvu/erQ=="}},"verification-keys":[{"type":"pkix-base64-key","value":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW1BvqF+/ry8BWa7ZEMU1xYYHEQ8B\nlLT4MFHOaO+ICTtIvrEeEpr/sfTAP66H2hCHdb5HEXKtRKod6QLcOLPA1Q==\n-----END PUBLIC KEY-----"}]}],"attester-verification-keys":[{"environment":{"instance":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}},"verification-keys":[{"type":"pkix-base64-key","value":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW1BvqF+/ry8BWa7ZEMU1xYYHEQ8B\nlLT4MFHOaO+ICTtIvrEeEpr/sfTAP66H2hCHdb5HEXKtRKod6QLcOLPA1Q==\n-----END PUBLIC KEY-----"}]}]}} + //a50065656e2d474201a10078206d792d6e733a61636d652d726f616472756e6e65722d737570706c656d656e740282a3006941434d45204c74642e01d8207468747470733a2f2f61636d652e6578616d706c6502820100a20069454d4341204c74642e0281020382a200781a6d792d6e733a61636d652d726f616472756e6e65722d626173650100a20078196d792d6e733a61636d652d726f616472756e6e65722d6f6c64010104a4008182a300a500d86f445502c000016941434d45204c74642e026a526f616452756e6e65720300040101d902264702deadbeefdead02d8255031fb5abf023e4992aa4e95f9c1503bfa81a200d8255031fb5abf023e4992aa4e95f9c1503bfa01aa01d90228020282820644abcdef00820644ffffffff03a201f403f504d9023044010203040544ffffffff064602005e100001075020010db8000000000000000000000068086c43303258373056484a484435094702deadbeefdead0a5031fb5abf023e4992aa4e95f9c1503bfa018182a300a500d8255031fb5abf023e4992aa4e95f9c1503bfa016941434d45204c74642e026a526f616452756e6e65720300040101d902264702deadbeefdead02d8255031fb5abf023e4992aa4e95f9c1503bfa81a200d8255031fb5abf023e4992aa4e95f9c1503bfa01aa01d90229020282820644abcdef00820644ffffffff03a300f401f403f504d9023044010203040544ffffffff064602005e100001075020010db8000000000000000000000068086c43303258373056484a484435094702deadbeefdead0a5031fb5abf023e4992aa4e95f9c1503bfa028182a101d902264702deadbeefdead81d9022a78b12d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741455731427671462b2f727938425761375a454d553178595948455138420a6c4c54344d46484f614f2b4943547449767245654570722f7366544150363648326843486462354845584b74524b6f6436514c634f4c504131513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d038182a101d8255031fb5abf023e4992aa4e95f9c1503bfa81d9022a78b12d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741455731427671462b2f727938425761375a454d553178595948455138420a6c4c54344d46484f614f2b4943547449767245654570722f7366544150363648326843486462354845584b74524b6f6436514c634f4c504131513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d + //{"lang":"en-GB","tag-identity":{"id":"my-ns:acme-roadrunner-supplement"},"entities":[{"name":"ACME Ltd.","regid":"https://acme.example","roles":["creator","tagCreator"]},{"name":"EMCA Ltd.","roles":["maintainer"]}],"linked-tags":[{"target":"my-ns:acme-roadrunner-base","rel":"supplements"},{"target":"my-ns:acme-roadrunner-old","rel":"replaces"}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.5.2.8192"},"vendor":"ACME Ltd.","model":"RoadRunner","layer":0,"index":1},"instance":{"type":"ueid","value":"At6tvu/erQ=="},"group":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}},"measurements":[{"key":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"},"value":{"svn":{"type":"exact-value","value":2},"digests":["sha-256-32;q83vAA==","sha-256-32;/////w=="],"flags":{"is-secure":false,"is-debug":true},"raw-value":{"type":"bytes","value":"AQIDBA=="},"raw-value-mask":"/////w==","mac-addr":"02:00:5e:10:00:01","ip-addr":"2001:db8::68","serial-number":"C02X70VHJHD5","ueid":"At6tvu/erQ==","uuid":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}}]}],"endorsed-values":[{"environment":{"class":{"id":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"},"vendor":"ACME Ltd.","model":"RoadRunner","layer":0,"index":1},"instance":{"type":"ueid","value":"At6tvu/erQ=="},"group":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}},"measurements":[{"key":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"},"value":{"svn":{"type":"min-value","value":2},"digests":["sha-256-32;q83vAA==","sha-256-32;/////w=="],"flags":{"is-configured":false,"is-secure":false,"is-debug":true},"raw-value":{"type":"bytes","value":"AQIDBA=="},"raw-value-mask":"/////w==","mac-addr":"02:00:5e:10:00:01","ip-addr":"2001:db8::68","serial-number":"C02X70VHJHD5","ueid":"At6tvu/erQ==","uuid":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}}]}],"dev-identity-keys":[{"environment":{"instance":{"type":"ueid","value":"At6tvu/erQ=="}},"verification-keys":[{"type":"pkix-base64-key","value":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW1BvqF+/ry8BWa7ZEMU1xYYHEQ8B\nlLT4MFHOaO+ICTtIvrEeEpr/sfTAP66H2hCHdb5HEXKtRKod6QLcOLPA1Q==\n-----END PUBLIC KEY-----"}]}],"attester-verification-keys":[{"environment":{"instance":{"type":"uuid","value":"31fb5abf-023e-4992-aa4e-95f9c1503bfa"}},"verification-keys":[{"type":"pkix-base64-key","value":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW1BvqF+/ry8BWa7ZEMU1xYYHEQ8B\nlLT4MFHOaO+ICTtIvrEeEpr/sfTAP66H2hCHdb5HEXKtRKod6QLcOLPA1Q==\n-----END PUBLIC KEY-----"}]}]}} } func Example_encode_PSA() { diff --git a/comid/measurement.go b/comid/measurement.go index 1977735..c64909f 100644 --- a/comid/measurement.go +++ b/comid/measurement.go @@ -424,6 +424,7 @@ func (o Mval) MarshalJSON() ([]byte, error) { } func (o Mval) Valid() error { + // Check if no measurement values are set if o.Ver == nil && o.SVN == nil && o.Digests == nil && @@ -439,28 +440,47 @@ func (o Mval) Valid() error { return fmt.Errorf("no measurement value set") } + // Validate Version if o.Ver != nil { if err := o.Ver.Valid(); err != nil { return err } } + // Validate Digests if o.Digests != nil { if err := o.Digests.Valid(); err != nil { return err } } + // Validate Flags if o.Flags != nil { if err := o.Flags.Valid(); err != nil { return err } } - // raw value and mask have no specific semantics + // Validate MAC Address + if o.MACAddr != nil { + macLen := len(*o.MACAddr) + if macLen != 6 && macLen != 8 { // MAC address must be either 6 or 8 bytes + return fmt.Errorf("invalid MAC address length: expected 6 or 8 bytes, got %d", macLen) + } + } + + // Validate IP Address + if o.IPAddr != nil { + ip := *o.IPAddr + // Must be valid IPv4 or IPv6 (i.e., .To4() != nil or .To16() != nil) + if ip.To4() == nil && ip.To16() == nil { + return fmt.Errorf("invalid IP address: %s", ip.String()) + } + } - // TODO(tho) MAC addr & friends (see https://github.com/veraison/corim/issues/18) + // raw value and raw-value-mask have no specific semantics here + // Validate extensions (custom logic implemented in validMval()) return o.Extensions.validMval(&o) } diff --git a/comid/measurement_test.go b/comid/measurement_test.go index 078c7ee..45505ea 100644 --- a/comid/measurement_test.go +++ b/comid/measurement_test.go @@ -6,6 +6,7 @@ package comid import ( "crypto" "fmt" + "net" "testing" "github.com/stretchr/testify/assert" @@ -601,3 +602,99 @@ func TestMkey_UintMkey(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 7, ret) } + +func TestMval_Valid(t *testing.T) { + t.Run("No fields set", func(t *testing.T) { + mval := Mval{} + err := mval.Valid() + assert.EqualError(t, err, "no measurement value set") + }) + + t.Run("All fields nil except Ver, which is valid", func(t *testing.T) { + var scheme swid.VersionScheme + _ = scheme.SetCode(swid.VersionSchemeSemVer) + mval := Mval{ + Ver: &Version{ + Version: "1.0", + Scheme: scheme, + }, + } + err := mval.Valid() + assert.NoError(t, err) + }) + + // Test with valid 6-byte MAC + t.Run("MACAddr valid (6 bytes)", func(t *testing.T) { + mac := MACaddr([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}) // EUI-48 + mval := Mval{MACAddr: &mac} + err := mval.Valid() + assert.NoError(t, err, "6-byte MAC should be valid") + }) + + // Test with valid 8-byte MAC + t.Run("MACAddr valid (8 bytes)", func(t *testing.T) { + mac := MACaddr([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}) // EUI-64 + mval := Mval{MACAddr: &mac} + err := mval.Valid() + assert.NoError(t, err, "8-byte MAC should be valid") + }) + + // Test with invalid MAC length + t.Run("MACAddr invalid (too many bytes)", func(t *testing.T) { + mac := MACaddr([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}) // 7 bytes + mval := Mval{MACAddr: &mac} + err := mval.Valid() + assert.EqualError(t, err, "invalid MAC address length: expected 6 or 8 bytes, got 7") + }) + + // Test with invalid MAC length + t.Run("MACAddr invalid (too few bytes)", func(t *testing.T) { + mac := MACaddr([]byte{0x01, 0x02, 0x03, 0x04}) // 4 bytes + mval := Mval{MACAddr: &mac} + err := mval.Valid() + assert.EqualError(t, err, "invalid MAC address length: expected 6 or 8 bytes, got 4") + }) + + t.Run("MACAddr valid (6 bytes)", func(t *testing.T) { + mac := MACaddr([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}) + mval := Mval{MACAddr: &mac} + err := mval.Valid() + assert.NoError(t, err) + }) + + t.Run("IPAddr valid (IPv4)", func(t *testing.T) { + ip := net.IPv4(192, 168, 1, 100) + mval := Mval{IPAddr: &ip} + err := mval.Valid() + assert.NoError(t, err) + }) + + t.Run("IPAddr valid (IPv6)", func(t *testing.T) { + ip := net.ParseIP("2001:db8::1") + mval := Mval{IPAddr: &ip} + err := mval.Valid() + assert.NoError(t, err) + }) + + t.Run("Digests valid", func(t *testing.T) { + ds := NewDigests() + _ = ds.AddDigest(swid.Sha256, []byte{0xAA, 0xBB}) + mval := Mval{ + Digests: ds, + } + err := mval.Valid() + assert.NoError(t, err) + }) + + t.Run("Extensions valid", func(t *testing.T) { + // Suppose we have some extension data that is considered valid + ext := Extensions{} + mval := Mval{ + Extensions: ext, + // Must also set one non-empty field to pass "no measurement value set" + Ver: &Version{Version: "1.0"}, + } + err := mval.Valid() + assert.NoError(t, err) + }) +} diff --git a/comid/test_vars.go b/comid/test_vars.go index eb7a29e..12d9c93 100644 --- a/comid/test_vars.go +++ b/comid/test_vars.go @@ -26,7 +26,7 @@ var ( }) TestOID = "2.5.2.8192" TestRegID = "https://acme.example" - TestMACaddr, _ = net.ParseMAC("02:00:5e:10:00:00:00:01") + TestMACaddr, _ = net.ParseMAC("02:00:5e:10:00:01") TestIPaddr = net.ParseIP("2001:db8::68") TestBytes = []byte{0x89, 0x99, 0x78, 0x65, 0x56} TestUEIDString = "02deadbeefdead"