diff --git a/cocli/data/comid/templates/comid-cca-realm-refval.json b/cocli/data/comid/templates/comid-cca-realm-refval.json new file mode 100644 index 00000000..965d9fd2 --- /dev/null +++ b/cocli/data/comid/templates/comid-cca-realm-refval.json @@ -0,0 +1,75 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "entities": [ + { + "name": "Workload Client Ltd.", + "regid": "https://workloadclient.example", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "uuid", + "value": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C" + }, + "vendor": "Workload Client Ltd" + }, + "instance": { + "type": "bytes", + "value": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + } + }, + "measurements": [ + { + "value": { + "integrity-registers": { + "rim": { + "key-type": "text", + "value": [ + "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + ] + }, + "rem0": { + "key-type": "text", + "value": [ + "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + }, + "rem1": { + "key-type": "text", + "value": [ + "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + }, + "rem2": { + "key-type": "text", + "value": [ + "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + }, + "rem3": { + "key-type": "text", + "value": [ + "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + } + } + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/cocli/data/corim/templates/corim-cca-realm.json b/cocli/data/corim/templates/corim-cca-realm.json new file mode 100644 index 00000000..8dfd86d0 --- /dev/null +++ b/cocli/data/corim/templates/corim-cca-realm.json @@ -0,0 +1,19 @@ +{ + "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", + "profiles": [ + "http://arm.com/cca/realm/1" + ], + "validity": { + "not-before": "2021-12-31T00:00:00Z", + "not-after": "2025-12-31T00:00:00Z" + }, + "entities": [ + { + "name": "ACME Ltd.", + "regid": "acme.example", + "roles": [ + "manifestCreator" + ] + } + ] +} \ No newline at end of file diff --git a/cocli/data/corim/templates/corim-cca.json b/cocli/data/corim/templates/corim-cca.json index ba2ce068..fb28d9ba 100644 --- a/cocli/data/corim/templates/corim-cca.json +++ b/cocli/data/corim/templates/corim-cca.json @@ -1,11 +1,5 @@ { "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", - "dependent-rims": [ - { - "href": "https://parent.example/rims/ccb3aa85-61b4-40f1-848e-02ad6e8a254b", - "thumbprint": "sha-256:5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" - } - ], "profiles": [ "http://arm.com/cca/ssd/1" ], diff --git a/comid/example_cca_realm_refval_test.go b/comid/example_cca_realm_refval_test.go new file mode 100644 index 00000000..1ef644ef --- /dev/null +++ b/comid/example_cca_realm_refval_test.go @@ -0,0 +1,207 @@ +// Copyright 2024 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package comid + +import ( + "fmt" + "strings" +) + +func Example_cca_realm_refval() { + comid := Comid{} + + if err := comid.FromJSON([]byte(CCARealmRefValJSONTemplate)); err != nil { + panic(err) + } + + if err := comid.Valid(); err != nil { + panic(err) + } + + if err := extractRealmRefVals(&comid); err != nil { + panic(err) + } + // output: + // Vendor: Workload Client Ltd + // ClassID: cd1f0e5526f9460db9d8f7fde171787c + // InstanceID: 4284b5694ca6c0d2cf4789a0b95ac8025c818de52304364be7cd2981b2d2edc685b322277ec25819962413d8c9b2c1f5 + // Index: rim + // Alg: sha-384 + // Digest: 4284b5694ca6c0d2cf4789a0b95ac8025c818de52304364be7cd2981b2d2edc685b322277ec25819962413d8c9b2c1f5 + // Index: rem0 + // Alg: sha-384 + // Digest: 2107bbe761fca52d95136a1354db7a4dd57b1b26be0d3da71d9eb23986b34ba615abf6514cf35e5a9ea55a032d068a78 + // Index: rem1 + // Alg: sha-384 + // Digest: 2507bbe761fca52d95136a1354db7a4dd57b1b26be0d3da71d9eb23986b34ba615abf6514cf35e5a9ea55a032d068a78 + // Index: rem2 + // Alg: sha-384 + // Digest: 3107bbe761fca52d95136a1354db7a4dd57b1b26be0d3da71d9eb23986b34ba615abf6514cf35e5a9ea55a032d068a78 + // Index: rem3 + // Alg: sha-384 + // Digest: 3507bbe761fca52d95136a1354db7a4dd57b1b26be0d3da71d9eb23986b34ba615abf6514cf35e5a9ea55a032d068a78 + +} + +func extractRealmRefVals(c *Comid) error { + if c.Triples.ReferenceValues == nil { + return fmt.Errorf("no reference values triples") + } + + for i, rv := range *c.Triples.ReferenceValues { + if err := extractRealmRefVal(rv); err != nil { + return fmt.Errorf("bad Realm reference value at index %d: %w", i, err) + } + } + + return nil +} + +func extractRealmRefVal(rv ReferenceValue) error { + class := rv.Environment.Class + instance := rv.Environment.Instance + + if err := extractRealmClass(class); err != nil { + return fmt.Errorf("extracting class: %w", err) + } + + if err := extractRealmInstanceID(instance); err != nil { + return fmt.Errorf("extracting realm instanceID: %w", err) + } + + measurements := rv.Measurements + + if err := extractMeasurements(measurements); err != nil { + return fmt.Errorf("extracting measurements: %w", err) + } + + return nil +} + +func extractMeasurements(m Measurements) error { + if len(m) == 0 { + return fmt.Errorf("no measurements") + } + + for i, m := range m { + if err := extractMeasurement(m); err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + } + + return nil +} + +func extractMeasurement(m Measurement) error { + if err := extractIntegrityRegisters(m.Val.IntegrityRegisters); err != nil { + return fmt.Errorf("extracting digest: %w", err) + } + + return nil +} + +func extractRealmClass(c *Class) error { + if c == nil { + fmt.Println("class not present") + return nil + } + + if c.Vendor != nil { + fmt.Printf("Vendor: %s\n", c.GetVendor()) + } + + classID := c.ClassID + if classID == nil { + fmt.Println("class-id not present") + return nil + } + + if classID.Type() != "uuid" { + return fmt.Errorf("class id is not a uuid") + } + if err := classID.Valid(); err != nil { + return fmt.Errorf("invalid uuid: %v", err) + } + fmt.Printf("ClassID: %x\n", classID.Bytes()) + + return nil +} + +func extractRealmInstanceID(i *Instance) error { + if i == nil { + return fmt.Errorf("no instance") + } + + if i.Type() != "bytes" { + return fmt.Errorf("instance id is not bytes") + } + + fmt.Printf("InstanceID: %x\n", i.Bytes()) + + return nil +} + +func extractIntegrityRegisters(r *IntegrityRegisters) error { + if r == nil { + return fmt.Errorf("no integrity registers") + } + + keys, err := extractRegisterIndexes(r) + if err != nil { + return fmt.Errorf("unable to extract register index: %v", err) + } + + for _, k := range keys { + d, ok := r.m[k] + if !ok { + return fmt.Errorf("unable to locate register index for: %s", k) + } + fmt.Printf("Index: %s\n", k) + if err := extractRealmDigests(d); err != nil { + return fmt.Errorf("invalid Digests for key: %s, %v", k, err) + } + } + + return nil +} + +func extractRealmDigests(digests Digests) error { + + if err := digests.Valid(); err != nil { + return fmt.Errorf("invalid digest: %v", err) + } + for _, d := range digests { + fmt.Printf("Alg: %s\n", d.AlgIDToString()) + fmt.Printf("Digest: %x\n", d.HashValue) + } + + return nil +} + +func extractRegisterIndexes(r *IntegrityRegisters) ([]string, error) { + var keys [5]string + for k := range r.m { + switch t := k.(type) { + case string: + key := strings.ToLower(t) + switch key { + case "rim": + keys[0] = key + case "rem0": + keys[1] = key + case "rem1": + keys[2] = key + case "rem2": + keys[3] = key + case "rem3": + keys[4] = key + default: + return nil, fmt.Errorf("unexpected register index: %s", key) + } + default: + return nil, fmt.Errorf("unexpected type for index: %T", t) + } + } + return keys[:], nil +} diff --git a/comid/integrityregisters.go b/comid/integrityregisters.go index 9a40850e..e0aec76f 100644 --- a/comid/integrityregisters.go +++ b/comid/integrityregisters.go @@ -63,8 +63,8 @@ func (i *IntegrityRegisters) UnmarshalCBOR(data []byte) error { } type keyTypeandVal struct { - KeyType string `json:"key_type"` - Value json.RawMessage + KeyType string `json:"key-type"` + Value json.RawMessage `json:"value"` } func (i IntegrityRegisters) MarshalJSON() ([]byte, error) { diff --git a/comid/integrityregisters_test.go b/comid/integrityregisters_test.go index 07c6cfe9..079956e9 100644 --- a/comid/integrityregisters_test.go +++ b/comid/integrityregisters_test.go @@ -98,32 +98,32 @@ func TestIntegrityRegisters_UnmarshalCBOR_UIntIndex_OK(t *testing.T) { func TestIntegrityRegisters_MarshalJSON_UIntIndex_OK(t *testing.T) { expected := `{ "0": { - "key_type": "uint", - "Value": [ + "key-type": "uint", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "1": { - "key_type": "uint", - "Value": [ + "key-type": "uint", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "2": { - "key_type": "uint", - "Value": [ + "key-type": "uint", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "3": { - "key_type": "uint", - "Value": [ + "key-type": "uint", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "4": { - "key_type": "uint", - "Value": [ + "key-type": "uint", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] } @@ -173,32 +173,32 @@ func TestIntegrityRegisters_UnmarshalCBOR_TextIndex_OK(t *testing.T) { func TestIntegrityRegisters_MarshalJSON_TextIndex_OK(t *testing.T) { expected := `{ "0": { - "key_type": "text", - "Value": [ + "key-type": "text", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "1": { - "key_type": "text", - "Value": [ + "key-type": "text", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "2": { - "key_type": "text", - "Value": [ + "key-type": "text", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "3": { - "key_type": "text", - "Value": [ + "key-type": "text", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] }, "4": { - "key_type": "text", - "Value": [ + "key-type": "text", + "value": [ "sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" ] } @@ -213,7 +213,7 @@ func TestIntegrityRegisters_MarshalJSON_TextIndex_OK(t *testing.T) { } func TestIntegrityRegisters_UnmarshalJSON_TextIndex_OK(t *testing.T) { - j := `{"abcd":{"key_type":"text","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}` + j := `{"abcd":{"key-type":"text","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}` expected := IntegrityRegisters{map[IRegisterIndex]Digests{ "abcd": []swid.HashEntry{{HashAlgID: swid.Sha256, HashValue: MustHexDecode(t, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75")}}, }} @@ -225,11 +225,11 @@ func TestIntegrityRegisters_UnmarshalJSON_TextIndex_OK(t *testing.T) { func TestIntegrityRegisters_UnmarshalJSON_UIntIndex_OK(t *testing.T) { j := `{ - "0":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "1":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "2":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "3":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "4":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]} + "0":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "1":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "2":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "3":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "4":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]} }` expected := IntegrityRegisters{map[IRegisterIndex]Digests{ uint(0): []swid.HashEntry{{HashAlgID: swid.Sha256, HashValue: MustHexDecode(t, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75")}}, @@ -246,11 +246,11 @@ func TestIntegrityRegisters_UnmarshalJSON_UIntIndex_OK(t *testing.T) { func TestIntegrityRegisters_UnmarshalJSON_TextUInt_Index_OK(t *testing.T) { j := `{ - "0":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "1":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "2":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "3":{"key_type":"text","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, - "4":{"key_type":"text","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]} + "0":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "1":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "2":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "3":{"key-type":"text","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}, + "4":{"key-type":"text","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]} }` expected := IntegrityRegisters{ map[IRegisterIndex]Digests{ @@ -274,22 +274,22 @@ func TestIntegrityRegisters_UnmarshalJSON_NOK(t *testing.T) { }{ { Name: "invalid input integer", - Input: `{"0":{"key_type":"int","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}`, + Input: `{"0":{"key-type":"int","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}`, Err: "unexpected key type for index: int", }, { Name: "negative index", - Input: `{"-1":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}`, + Input: `{"-1":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}`, Err: `invalid negative integer key`, }, { Name: "not an integer", - Input: `{"0.2345":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}`, + Input: `{"0.2345":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="]}}`, Err: `unable to convert key to uint: strconv.Atoi: parsing "0.2345": invalid syntax`, }, { Name: "invalid digest", - Input: `{"1":{"key_type":"uint","Value":["sha-256;5Fty9cDAtXLbTY06t+l/3TmI0eoJN7LZ6hOUiTXU="]}}`, + Input: `{"1":{"key-type":"uint","value":["sha-256;5Fty9cDAtXLbTY06t+l/3TmI0eoJN7LZ6hOUiTXU="]}}`, Err: `unable to unmarshal Digests: illegal base64 data at input byte 40`, }, } { diff --git a/comid/measurement.go b/comid/measurement.go index 77d76211..469e611d 100644 --- a/comid/measurement.go +++ b/comid/measurement.go @@ -355,7 +355,8 @@ func (o Mval) Valid() error { o.IPAddr == nil && o.SerialNumber == nil && o.UEID == nil && - o.UUID == nil { + o.UUID == nil && + o.IntegrityRegisters == nil { return fmt.Errorf("no measurement value set") } diff --git a/comid/test_vars.go b/comid/test_vars.go index ef647dad..7c5969e7 100644 --- a/comid/test_vars.go +++ b/comid/test_vars.go @@ -439,4 +439,79 @@ var ( } } ` + CCARealmRefValJSONTemplate = `{ + "lang": "en-GB", + "tag-identity": { + "id": "99019224-57AA-44BC-BEF8-D36BDD6BD035", + "version": 0 +}, +"entities": [ + { + "name": "Workload Client Ltd.", + "regid": "https://workloadclient.example", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } +], +"triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "uuid", + "value": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C" + }, + "vendor": "Workload Client Ltd" + }, + "instance": { + "type": "bytes", + "value": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + } + }, + "measurements": [ + { + "value": { + "integrity-registers": { + "rim": { + "key-type": "text", + "value": [ + "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + ] + }, + "rem0": { + "key-type": "text", + "value": [ + "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + }, + "rem1": { + "key-type": "text", + "value": [ + "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + }, + "rem2": { + "key-type": "text", + "value": [ + "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + }, + "rem3": { + "key-type": "text", + "value": [ + "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + ] + } + } + } + } + ] + } + ] +} +}` )