From cd063839c98c96399d3ac6bd6e0657da019bb279 Mon Sep 17 00:00:00 2001 From: Yogesh Deshpande Date: Fri, 20 Sep 2024 12:13:50 +0100 Subject: [PATCH] Introduce TDX profile Signed-off-by: Yogesh Deshpande --- README.md | 1 + comid/digests_test.go | 2 - comid/measurement.go | 2 + comid/tdx-profile/*.cbor | 0 comid/tdx-profile/example_pce_refval_test.go | 329 +++++++++++ comid/tdx-profile/example_qe_refval_test.go | 303 +++++++++++ comid/tdx-profile/example_seam_refval_test.go | 510 ++++++++++++++++++ comid/tdx-profile/mval_extensions.go | 55 ++ comid/tdx-profile/teeadvisoryids.go | 51 ++ comid/tdx-profile/teeadvisoryids_test.go | 73 +++ comid/tdx-profile/teeattributes.go | 24 + comid/tdx-profile/teeattributes_test.go | 31 ++ comid/tdx-profile/teeinstanceid.go | 171 ++++++ comid/tdx-profile/teeinstanceid_test.go | 115 ++++ comid/tdx-profile/teeisvproid.go | 170 ++++++ comid/tdx-profile/teeisvproid_test.go | 118 ++++ comid/tdx-profile/teemiscselect.go | 24 + comid/tdx-profile/teemiscselect_test.go | 31 ++ comid/tdx-profile/teepceid.go | 23 + comid/tdx-profile/teepceid_test.go | 31 ++ comid/tdx-profile/teetcbcompsvn.go | 29 + comid/tdx-profile/teetcbstatus.go | 51 ++ comid/tdx-profile/teetcbstatus_test.go | 74 +++ comid/tdx-profile/test_vars.go | 187 +++++++ .../testcases/comid_pce_refval.cbor | Bin 0 -> 382 bytes .../testcases/comid_qe_refval.cbor | Bin 0 -> 432 bytes .../testcases/comid_seam_refval.cbor | Bin 0 -> 456 bytes comid/tdx-profile/testcases/regen-from-src.sh | 21 + .../testcases/src/comid_pce_refval.diag | 34 ++ .../testcases/src/comid_qe_refval.diag | 44 ++ .../testcases/src/comid_seam_refval.diag | 51 ++ comid/tdx-profile/types.go | 11 + comid/test_vars.go | 1 + comid/triples.go | 2 +- 34 files changed, 2566 insertions(+), 3 deletions(-) create mode 100644 comid/tdx-profile/*.cbor create mode 100644 comid/tdx-profile/example_pce_refval_test.go create mode 100644 comid/tdx-profile/example_qe_refval_test.go create mode 100644 comid/tdx-profile/example_seam_refval_test.go create mode 100644 comid/tdx-profile/mval_extensions.go create mode 100644 comid/tdx-profile/teeadvisoryids.go create mode 100644 comid/tdx-profile/teeadvisoryids_test.go create mode 100644 comid/tdx-profile/teeattributes.go create mode 100644 comid/tdx-profile/teeattributes_test.go create mode 100644 comid/tdx-profile/teeinstanceid.go create mode 100644 comid/tdx-profile/teeinstanceid_test.go create mode 100644 comid/tdx-profile/teeisvproid.go create mode 100644 comid/tdx-profile/teeisvproid_test.go create mode 100644 comid/tdx-profile/teemiscselect.go create mode 100644 comid/tdx-profile/teemiscselect_test.go create mode 100644 comid/tdx-profile/teepceid.go create mode 100644 comid/tdx-profile/teepceid_test.go create mode 100644 comid/tdx-profile/teetcbcompsvn.go create mode 100644 comid/tdx-profile/teetcbstatus.go create mode 100644 comid/tdx-profile/teetcbstatus_test.go create mode 100644 comid/tdx-profile/test_vars.go create mode 100644 comid/tdx-profile/testcases/comid_pce_refval.cbor create mode 100644 comid/tdx-profile/testcases/comid_qe_refval.cbor create mode 100644 comid/tdx-profile/testcases/comid_seam_refval.cbor create mode 100755 comid/tdx-profile/testcases/regen-from-src.sh create mode 100644 comid/tdx-profile/testcases/src/comid_pce_refval.diag create mode 100644 comid/tdx-profile/testcases/src/comid_qe_refval.diag create mode 100644 comid/tdx-profile/testcases/src/comid_seam_refval.diag create mode 100644 comid/tdx-profile/types.go diff --git a/README.md b/README.md index d118c42f..0024b169 100644 --- a/README.md +++ b/README.md @@ -37,3 +37,4 @@ and giving it a new type or a value (for enums). Please see [extensions documentation](extensions/README.md) for details. + diff --git a/comid/digests_test.go b/comid/digests_test.go index ff14b359..663a064d 100644 --- a/comid/digests_test.go +++ b/comid/digests_test.go @@ -76,7 +76,6 @@ func TestDigests_AddDigest_OK(t *testing.T) { assert.Nil(t, d.Valid()) } } - func TestDigests_Valid_empty(t *testing.T) { d := NewDigests() require.NotNil(t, d) @@ -89,7 +88,6 @@ func TestDigests_Valid_empty(t *testing.T) { assert.EqualError(t, d.Valid(), "digest at index 0: unknown hash algorithm 666") } - func TestDigests_AddDigest_unknown_algo(t *testing.T) { d := NewDigests() require.NotNil(t, d) diff --git a/comid/measurement.go b/comid/measurement.go index 08a54419..895463ce 100644 --- a/comid/measurement.go +++ b/comid/measurement.go @@ -441,7 +441,9 @@ func (o Mval) Valid() error { o.UEID == nil && o.UUID == nil && o.IntegrityRegisters == nil && + o.Extensions.IsEmpty() { + // Check for Value as well, need an API to add something return fmt.Errorf("no measurement value set") } diff --git a/comid/tdx-profile/*.cbor b/comid/tdx-profile/*.cbor new file mode 100644 index 00000000..e69de29b diff --git a/comid/tdx-profile/example_pce_refval_test.go b/comid/tdx-profile/example_pce_refval_test.go new file mode 100644 index 00000000..1df3ef09 --- /dev/null +++ b/comid/tdx-profile/example_pce_refval_test.go @@ -0,0 +1,329 @@ +// Copyright 2024 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + _ "embed" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/eat" +) + +// Example_decode_PCE_JSON decodes the TDX Provisioning Certification Enclave Measurement Extensions from the given JSON Template +func Example_decode_PCE_JSON() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + if err := m.FromJSON([]byte(TDXPCERefValTemplate)); err != nil { + panic(err) + } + + if err := m.Valid(); err != nil { + panic(err) + } + + if err := extractPCERefVals(m); err != nil { + panic(err) + } + + // output: + // OID: 2.16.840.1.113741.1.2.3.4.6 + // Vendor: Intel Corporation + // Model: 0123456789ABCDEF + // InstanceID: 11 + // pceID: 0000 + // SVN[0]: 10 + // SVN[1]: 10 + // SVN[2]: 2 + // SVN[3]: 2 + // SVN[4]: 2 + // SVN[5]: 1 + // SVN[6]: 4 + // SVN[7]: 0 + // SVN[8]: 0 + // SVN[9]: 0 + // SVN[10]: 0 + // SVN[11]: 0 + // SVN[12]: 0 + // SVN[13]: 0 + // SVN[14]: 0 + // SVN[15]: 0 + // CryptoKey Type: pkix-base64-key + // CryptoKey Value: -----BEGIN PUBLIC KEY----- + // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg== + // -----END PUBLIC KEY----- +} + +func extractPCERefVals(c *comid.Comid) error { + if c.Triples.ReferenceValues == nil { + return fmt.Errorf("no reference values triples") + } + + for i, rv := range c.Triples.ReferenceValues.Values { + if err := extractPCERefVal(rv); err != nil { + return fmt.Errorf("bad PSA reference value at index %d: %w", i, err) + } + } + + return nil +} + +func extractPCERefVal(rv comid.ValueTriple) error { + class := rv.Environment.Class + + if err := extractClassElements(class); err != nil { + return fmt.Errorf("extracting class: %w", err) + } + + measurements := rv.Measurements + if err := extractPCEMeasurements(&measurements); err != nil { + return fmt.Errorf("extracting measurements: %w", err) + } + + return nil +} + +func extractPCEMeasurements(meas *comid.Measurements) error { + if len(meas.Values) == 0 { + return fmt.Errorf("no measurements") + } + for i := range meas.Values { + m := &meas.Values[0] + if err := decodePCEMValExtensions(m); err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + + if m.AuthorizedBy != nil { + err := decodeAuthorisedBy(m) + if err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + } + } + return nil +} + +func decodePCEMValExtensions(m *comid.Measurement) error { + val, err := m.Val.Extensions.Get("instanceid") + if err != nil { + return fmt.Errorf("failed to decode instanceid from measurement extensions") + } + i, ok := val.(*TeeInstanceID) + if !ok { + fmt.Printf("val was not pointer to teeInstanceID") + } + + if i.IsBytesInstanceID() { + val, err = i.GetBytesInstanceID() + if err != nil { + return fmt.Errorf("failed to decode instanceid: %w", err) + } + fmt.Printf("\nInstanceID: %x", val) + } else if i.IsUintInstanceID() { + val, err = i.GetUintInstanceID() + if err != nil { + return fmt.Errorf("failed to decode instanceid: %w", err) + } + fmt.Printf("\nInstanceID: %d", val) + } else { + return fmt.Errorf("instanceid is neither integer or byte string") + } + + val, err = m.Val.Extensions.Get("tcbcompsvn") + if err != nil { + return fmt.Errorf("failed to decode tcbcompsvn from measurement extensions") + } + + tD, ok := val.(*TeeTcbCompSvn) + if !ok { + fmt.Printf("val was not pointer to tcbcompsvn") + } + if err = tD.Valid(); err != nil { + return fmt.Errorf("invalid computed SVN: %w", err) + } + val, err = m.Val.Extensions.Get("pceid") + if err != nil { + return fmt.Errorf("failed to decode tcbevalnum from measurement extensions") + } + t, ok := val.(*TeePCEID) + if !ok { + fmt.Printf("val was not pointer to TeeTcbEvalNum") + } + if err = t.Valid(); err != nil { + return fmt.Errorf("invalid PCEID: %w", err) + } + pceID := *t + fmt.Printf("\npceID: %s", pceID) + + err = extractSVN(tD) + if err != nil { + return fmt.Errorf("unable to extract TEE Digest: %w", err) + } + return nil +} + +func extractSVN(s *TeeTcbCompSvn) error { + if s == nil { + return fmt.Errorf("no TEE TCB Comp SVN") + } + + if len(*s) > 16 { + return fmt.Errorf("computed SVN cannot be greater than 16") + } + + for i, svn := range *s { + fmt.Printf("\nSVN[%d]: %d", i, svn) + } + + return nil +} + +var ( + // test cases are based on diag files here: + // https://github.com/ietf-rats-wg/draft-ietf-rats-corim/tree/main/cddl/examples + + //go:embed testcases/comid_pce_refval.cbor + testComid3 []byte +) + +func Example_decode_PCE_CBOR() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + + if err := m.FromCBOR(testComid3); err != nil { + panic(err) + } + if err := m.Valid(); err != nil { + panic(err) + } + + if err := extractPCERefVals(m); err != nil { + panic(err) + } + + // Output: + // OID: 2.16.840.1.113741.1.2.3.4.5 + // Vendor: Intel Corporation + // Model: TDX PCE TCB + // InstanceID: 00112233445566778899aabbccddeeff + // pceID: 0000 + // SVN[0]: 10 + // SVN[1]: 10 + // SVN[2]: 2 + // SVN[3]: 2 + // SVN[4]: 2 + // SVN[5]: 1 + // SVN[6]: 4 + // SVN[7]: 0 + // SVN[8]: 0 + // SVN[9]: 0 + // SVN[10]: 0 + // SVN[11]: 0 + // SVN[12]: 0 + // SVN[13]: 0 + // SVN[14]: 0 + // SVN[15]: 0 + // CryptoKey Type: pkix-base64-key + // CryptoKey Value: -----BEGIN PUBLIC KEY----- + // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg== + // -----END PUBLIC KEY----- +} + +func Example_encode_tdx_pce_refval_with_profile() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + if m == nil { + panic(err) + } + m.SetTagIdentity("43BBE37F-2E61-4B33-AED3-53CFF1428B20", 0). + AddEntity("INTEL", &TestRegID, comid.RoleCreator, comid.RoleTagCreator, comid.RoleMaintainer) + + refVal := &comid.ValueTriple{} + measurement := &comid.Measurement{} + refVal.Environment = comid.Environment{ + Class: comid.NewClassOID(TestOID). + SetVendor("Intel Corporation"). + SetModel("TDX PCE TCB"), + } + + refVal.Measurements.Add(measurement) + m.Triples.AddReferenceValue(*refVal) + + err = setTDXPCEMvalExtension(&m.Triples.ReferenceValues.Values[0].Measurements.Values[0].Val) + if err != nil { + fmt.Printf("unable to set extensions :%s", err.Error()) + } + + err = m.Valid() + if err != nil { + fmt.Printf("CoMID is not Valid :%s", err.Error()) + } + + cbor, err := m.ToCBOR() + if err == nil { + fmt.Printf("%x\n", cbor) + } else { + fmt.Printf("\n To CBOR Failed: %s \n", err.Error()) + } + + json, err := m.ToJSON() + if err == nil { + fmt.Printf("%s\n", string(json)) + } else { + fmt.Printf("\n To JSON Failed \n") + } + + // Output: + // a301a1005043bbe37f2e614b33aed353cff1428b200281a30065494e54454c01d8207168747470733a2f2f696e74656c2e636f6d028301000204a1008182a100a300d86f4c6086480186f84d01020304050171496e74656c20436f72706f726174696f6e026b544458205043452054434281a101a3384c182d384f685043454944303031387c900102030405060708090a0b0c0d0e0f10 + // {"tag-identity":{"id":"43bbe37f-2e61-4b33-aed3-53cff1428b20"},"entities":[{"name":"INTEL","regid":"https://intel.com","roles":["creator","tagCreator","maintainer"]}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.16.840.1.113741.1.2.3.4.5"},"vendor":"Intel Corporation","model":"TDX PCE TCB"}},"measurements":[{"value":{"instanceid":{"type":"uint","value":45},"pceid":"PCEID001","tcbcompsvn":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}}]}]}} +} + +func setTDXPCEMvalExtension(val *comid.Mval) error { + instanceID := NewInstanceID(TestUIntInstance) + err := val.Extensions.Set("instanceid", instanceID) + if err != nil { + return fmt.Errorf("unable to set instanceID %w", err) + } + + p := NewPCEID(TestPCEID) + err = val.Extensions.Set("pceid", p) + if err != nil { + return fmt.Errorf("unable to set pceID %w", err) + } + + c := NewTeeTcbCompSVN(TestCompSVN) + err = val.Extensions.Set("tcbcompsvn", c) + if err != nil { + return fmt.Errorf("unable to set tcbcompsvn: %w", err) + } + return nil +} diff --git a/comid/tdx-profile/example_qe_refval_test.go b/comid/tdx-profile/example_qe_refval_test.go new file mode 100644 index 00000000..ff569bd7 --- /dev/null +++ b/comid/tdx-profile/example_qe_refval_test.go @@ -0,0 +1,303 @@ +// Copyright 2024 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + _ "embed" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/swid" +) + +// Example_decode_QE_JSON decodes the TDX Quoting Enclave Measurement Extensions from the given JSON Template +func Example_decode_QE_JSON() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + if err := m.FromJSON([]byte(TDXQERefValTemplate)); err != nil { + panic(err) + } + + if err := m.Valid(); err != nil { + panic(err) + } + + if err := extractQERefVals(m); err != nil { + panic(err) + } + + // output: + // OID: 2.16.840.1.113741.1.2.3.4.1 + // Vendor: Intel Corporation + // Model: TDX QE TCB + // miscselect: c0000000fbff0000 + // tcbEvalNum: 11 + // IsvProdID: 0303 + // mrsigner Digest Alg: 1 + // mrsigner Digest Value: 87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7 + // mrsigner Digest Alg: 8 + // mrsigner Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6aa314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // CryptoKey Type: pkix-base64-key + // CryptoKey Value: -----BEGIN PUBLIC KEY----- + // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg== + // -----END PUBLIC KEY----- +} + +func extractQERefVals(c *comid.Comid) error { + if c.Triples.ReferenceValues == nil { + return fmt.Errorf("no reference values triples") + } + + for i, rv := range c.Triples.ReferenceValues.Values { + if err := extractQERefVal(rv); err != nil { + return fmt.Errorf("bad PSA reference value at index %d: %w", i, err) + } + } + + return nil +} + +func extractQERefVal(rv comid.ValueTriple) error { + class := rv.Environment.Class + + if err := extractClassElements(class); err != nil { + return fmt.Errorf("extracting class: %w", err) + } + + measurements := rv.Measurements + if err := extractQEMeasurements(&measurements); err != nil { + return fmt.Errorf("extracting measurements: %w", err) + } + + return nil +} + +func extractQEMeasurements(meas *comid.Measurements) error { + if len(meas.Values) == 0 { + return fmt.Errorf("no measurements") + } + for i := range meas.Values { + m := &meas.Values[0] + if err := decodeQEMValExtensions(m); err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + + if m.AuthorizedBy != nil { + err := decodeAuthorisedBy(m) + if err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + } + } + return nil +} + +func decodeQEMValExtensions(m *comid.Measurement) error { + val, err := m.Val.Extensions.Get("miscselect") + if err != nil { + return fmt.Errorf("failed to decode miscselect from measurement extensions") + } + f, ok := val.(*TeeMiscSelect) + if !ok { + fmt.Printf("val was not pointer to TeeMiscSelect") + } + miscselect := *f + fmt.Printf("\nmiscselect: %x", miscselect) + + val, err = m.Val.Extensions.Get("tcbevalnum") + if err != nil { + return fmt.Errorf("failed to decode tcbevalnum from measurement extensions") + } + t, ok := val.(*TeeTcbEvalNum) + if !ok { + fmt.Printf("val was not pointer to TeeTcbEvalNum") + } + tcbValNum := *t + fmt.Printf("\ntcbEvalNum: %d", tcbValNum) + + val, err = m.Val.Extensions.Get("isvprodid") + if err != nil { + return fmt.Errorf("failed to decode isvprodid from measurement extensions") + } + tS, ok := val.(*TeeIsvProdID) + if !ok { + fmt.Printf("val was not pointer to IsvProdID") + } + + if tS.IsBytesIsvProdID() { + val, err = tS.GetBytesIsvProdID() + if err != nil { + return fmt.Errorf("failed to decode isvprodid: %w", err) + } + fmt.Printf("\nIsvProdID: %x", val) + } else if tS.IsUintIsvProdID() { + val, err = tS.GetUintIsvProdID() + if err != nil { + return fmt.Errorf("failed to decode isvprodid: %w", err) + } + fmt.Printf("\nIsvProdID: %d", val) + } else { + return fmt.Errorf("isvprodid is neither integer or byte string") + } + + val, err = m.Val.Extensions.Get("mrsigner") + if err != nil { + return fmt.Errorf("failed to decode mrsigner from measurement extensions") + } + + tD, ok := val.(*TeeDigest) + if !ok { + fmt.Printf("val was not pointer to TeeDigest") + } + + err = extractDigest("mrsigner", tD) + if err != nil { + return fmt.Errorf("unable to extract TEE Digest: %w", err) + } + return nil +} + +func Example_encode_tdx_QE_refval_without_profile() { + refVal := &comid.ValueTriple{} + measurement := &comid.Measurement{} + refVal.Environment = comid.Environment{ + Class: comid.NewClassOID(TestOID). + SetVendor("Intel Corporation"). + SetModel("0123456789ABCDEF"), // From irim-qe-cend.diag, CPUID[0x01].EAX.FMSP & 0x0FFF0FF0 + } + + extMap := extensions.NewMap(). + Add(comid.ExtReferenceValue, &MValExtensions{}) + + m := comid.NewComid(). + SetTagIdentity("43BBE37F-2E61-4B33-AED3-53CFF1428B20", 0). + AddEntity("INTEL", &TestRegID, comid.RoleCreator, comid.RoleTagCreator, comid.RoleMaintainer) + + refVal.Measurements.Add(measurement) + m.Triples.AddReferenceValue(*refVal) + if err := m.RegisterExtensions(extMap); err != nil { + panic(err) + } + + if err := setTDXQEMvalExtensions(&m.Triples.ReferenceValues.Values[0].Measurements.Values[0].Val); err != nil { + panic(err) + } + if err := m.Valid(); err != nil { + panic(err) + } + + cbor, err := m.ToCBOR() + if err == nil { + fmt.Printf("%x\n", cbor) + } else { + fmt.Printf("To CBOR failed \n") + } + + json, err := m.ToJSON() + if err == nil { + fmt.Printf("%s\n", string(json)) + } else { + fmt.Printf("To JSON failed \n") + } + + // Output: + // a301a1005043bbe37f2e614b33aed353cff1428b200281a30065494e54454c01d8207168747470733a2f2f696e74656c2e636f6d028301000204a1008182a100a300d86f4c6086480186f84d01020304050171496e74656c20436f72706f726174696f6e02703031323334353637383941424344454681a101a538480a385046c000fbff000038538282015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7582075830e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75e45b72f5c0c0b572db4d8d3ab7e97f3638540138550b + // {"tag-identity":{"id":"43bbe37f-2e61-4b33-aed3-53cff1428b20"},"entities":[{"name":"INTEL","regid":"https://intel.com","roles":["creator","tagCreator","maintainer"]}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.16.840.1.113741.1.2.3.4.5"},"vendor":"Intel Corporation","model":"0123456789ABCDEF"}},"measurements":[{"value":{"isvsvn":10,"miscselect":"wAD7/wAA","mrsigner":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=","sha-384;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82"],"isvprodid":{"type":"uint","value":1},"tcbevalnum":11}}]}]}} +} + +func setTDXQEMvalExtensions(val *comid.Mval) error { + svn := TeeSVN(10) + teeTcbEvNum := TeeTcbEvalNum(11) + teeMiscSel := TeeMiscSelect([]byte{0xC0, 0x00, 0xFB, 0xFF, 0x00, 0x00}) // Taken from irim-qe-ref.diag + // Taken below from irim-qe-ref.diag + r := 1 + isvProdID := NewISVProdID(r) + err := val.Extensions.Set("isvprodid", isvProdID) + if err != nil { + return fmt.Errorf("unable to set isvprodid %w", err) + } + err = val.Extensions.Set("isvsvn", &svn) + if err != nil { + return fmt.Errorf("unable to set isvsvn %w", err) + } + err = val.Extensions.Set("tcbevalnum", &teeTcbEvNum) + if err != nil { + return fmt.Errorf("unable to set tcbevalnum %w", err) + } + err = val.Extensions.Set("miscselect", &teeMiscSel) + if err != nil { + return fmt.Errorf("unable to set miscselect %w", err) + } + + d := comid.NewDigests() + d.AddDigest(swid.Sha256, comid.MustHexDecode(nil, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75")) + d.AddDigest(swid.Sha384, comid.MustHexDecode(nil, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75e45b72f5c0c0b572db4d8d3ab7e97f36")) + + err = val.Extensions.Set("mrsigner", d) + if err != nil { + return fmt.Errorf("unable to set mrsigner %w", err) + } + return nil +} + +var ( + // test cases are based on diag files here: + // https://github.com/ietf-rats-wg/draft-ietf-rats-corim/tree/main/cddl/examples + + //go:embed testcases/comid_qe_refval.cbor + testComid2 []byte +) + +func Example_decode_QE_CBOR() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + + if err := m.FromCBOR(testComid2); err != nil { + panic(err) + } + if err := m.Valid(); err != nil { + panic(err) + } + + if err := extractQERefVals(m); err != nil { + panic(err) + } + + // output: + // OID: 2.16.840.1.113741.1.2.3.4.1 + // Vendor: Intel Corporation + // Model: SGX QE TCB + // miscselect: a0b0c0d000000000 + // tcbEvalNum: 11 + // IsvProdID: 1 + // mrsigner Digest Alg: 1 + // mrsigner Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // mrsigner Digest Alg: 8 + // mrsigner Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6aa314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // CryptoKey Type: pkix-base64-key + // CryptoKey Value: -----BEGIN PUBLIC KEY----- + // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg== + // -----END PUBLIC KEY----- +} diff --git a/comid/tdx-profile/example_seam_refval_test.go b/comid/tdx-profile/example_seam_refval_test.go new file mode 100644 index 00000000..94b3af04 --- /dev/null +++ b/comid/tdx-profile/example_seam_refval_test.go @@ -0,0 +1,510 @@ +// Copyright 2024 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + _ "embed" + "fmt" + "log" + "time" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/swid" +) + +// Example_decode_JSON decodes the TDX Measurement Extensions from the given JSON Template +func Example_decode_JSON() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + if err := m.FromJSON([]byte(TDXSeamRefValJSONTemplate)); err != nil { + panic(err) + } + + if err := m.Valid(); err != nil { + panic(err) + } + + if err := extractRefVals(m); err != nil { + panic(err) + } + + // output: + // OID: 2.16.840.1.113741.1.2.3.4.5 + // Vendor: Intel Corporation + // Model: TDX SEAM + // tcbEvalNum: 11 + // IsvProdID: 0303 + // ISVSVN: 10 + // Attributes: f00a0b + // mrtee Digest Alg: 1 + // mrtee Digest Value: 87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7 + // mrsigner Digest Alg: 1 + // mrsigner Digest Value: 87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7 + // mrsigner Digest Alg: 8 + // mrsigner Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6aa314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // CryptoKey Type: pkix-base64-key + // CryptoKey Value: -----BEGIN PUBLIC KEY----- + // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg== + // -----END PUBLIC KEY----- +} + +func Example_encode_tdx_seam_refval_without_profile() { + refVal := &comid.ValueTriple{} + measurement := &comid.Measurement{} + refVal.Environment = comid.Environment{ + Class: comid.NewClassOID(TestOID). + SetVendor("Intel Corporation"). + SetModel("TDXSEAM"), + } + + extMap := extensions.NewMap(). + Add(comid.ExtReferenceValue, &MValExtensions{}) + + m := comid.NewComid(). + SetTagIdentity("43BBE37F-2E61-4B33-AED3-53CFF1428B20", 0). + AddEntity("INTEL", &TestRegID, comid.RoleCreator, comid.RoleTagCreator, comid.RoleMaintainer) + + refVal.Measurements.Add(measurement) + m.Triples.AddReferenceValue(*refVal) + if err := m.RegisterExtensions(extMap); err != nil { + panic(err) + } + + if err := setTDXSeamMvalExtensions(&m.Triples.ReferenceValues.Values[0].Measurements.Values[0].Val); err != nil { + panic(err) + } + if err := m.Valid(); err != nil { + panic(err) + } + + cbor, err := m.ToCBOR() + if err == nil { + fmt.Printf("%x\n", cbor) + } else { + fmt.Printf("To CBOR failed \n") + } + + json, err := m.ToJSON() + if err == nil { + fmt.Printf("%s\n", string(json)) + } else { + fmt.Printf("To JSON failed \n") + } + + // Output: + // a301a1005043bbe37f2e614b33aed353cff1428b200281a30065494e54454c01d8207168747470733a2f2f696e74656c2e636f6d028301000204a1008182a100a300d86f4c6086480186f84d01020304050171496e74656c20436f72706f726174696f6e02675444585345414d81a101a73847c11a6796cc8038480a385142010138528182015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7538538282015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7582075830e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75e45b72f5c0c0b572db4d8d3ab7e97f36385442010138550b + // {"tag-identity":{"id":"43bbe37f-2e61-4b33-aed3-53cff1428b20"},"entities":[{"name":"INTEL","regid":"https://intel.com","roles":["creator","tagCreator","maintainer"]}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.16.840.1.113741.1.2.3.4.5"},"vendor":"Intel Corporation","model":"TDXSEAM"}},"measurements":[{"value":{"tcbdate":"2025-01-27T00:00:00Z","isvsvn":10,"attributes":"AQE=","mrtee":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="],"mrsigner":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=","sha-384;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82"],"isvprodid":{"type":"bytes","value":"AQE="},"tcbevalnum":11}}]}]}} +} + +func Example_encode_tdx_seam_refval_with_profile() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + if m == nil { + panic(err) + } + m.SetTagIdentity("43BBE37F-2E61-4B33-AED3-53CFF1428B20", 0). + AddEntity("INTEL", &TestRegID, comid.RoleCreator, comid.RoleTagCreator, comid.RoleMaintainer) + + refVal := &comid.ValueTriple{} + measurement := &comid.Measurement{} + refVal.Environment = comid.Environment{ + Class: comid.NewClassOID(TestOID). + SetVendor("Intel Corporation"). + SetModel("TDXSEAM"), + } + + refVal.Measurements.Add(measurement) + m.Triples.AddReferenceValue(*refVal) + + err = setTDXSeamMvalExtensions(&m.Triples.ReferenceValues.Values[0].Measurements.Values[0].Val) + if err != nil { + fmt.Printf("unable to set extensions :%s", err.Error()) + } + + err = m.Valid() + if err != nil { + fmt.Printf("CoMID is not Valid :%s", err.Error()) + } + + cbor, err := m.ToCBOR() + if err == nil { + fmt.Printf("%x\n", cbor) + } else { + fmt.Printf("\n To CBOR Failed: %s \n", err.Error()) + } + + json, err := m.ToJSON() + if err == nil { + fmt.Printf("%s\n", string(json)) + } else { + fmt.Printf("\n To JSON Failed \n") + } + + // Output: + // a301a1005043bbe37f2e614b33aed353cff1428b200281a30065494e54454c01d8207168747470733a2f2f696e74656c2e636f6d028301000204a1008182a100a300d86f4c6086480186f84d01020304050171496e74656c20436f72706f726174696f6e02675444585345414d81a101a73847c11a6796cc8038480a385142010138528182015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7538538282015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7582075830e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75e45b72f5c0c0b572db4d8d3ab7e97f36385442010138550b + // {"tag-identity":{"id":"43bbe37f-2e61-4b33-aed3-53cff1428b20"},"entities":[{"name":"INTEL","regid":"https://intel.com","roles":["creator","tagCreator","maintainer"]}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.16.840.1.113741.1.2.3.4.5"},"vendor":"Intel Corporation","model":"TDXSEAM"}},"measurements":[{"value":{"tcbdate":"2025-01-27T00:00:00Z","isvsvn":10,"attributes":"AQE=","mrtee":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="],"mrsigner":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=","sha-384;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82"],"isvprodid":{"type":"bytes","value":"AQE="},"tcbevalnum":11}}]}]}} +} + +func Example_encode_tdx_seam_refval_direct() { + refVal := &comid.ValueTriple{} + measurement := &comid.Measurement{} + refVal.Environment = comid.Environment{ + Class: comid.NewClassOID(TestOID). + SetVendor("Intel Corporation"). + SetModel("TDXSEAM"), + } + + extMap := extensions.NewMap().Add(comid.ExtMval, &MValExtensions{}) + m := comid.NewComid(). + SetTagIdentity("43BBE37F-2E61-4B33-AED3-53CFF1428B20", 0). + AddEntity("INTEL", &TestRegID, comid.RoleCreator, comid.RoleTagCreator, comid.RoleMaintainer) + + if err := measurement.Val.RegisterExtensions(extMap); err != nil { + log.Fatal("could not register mval extensions") + } + + if err := setTDXSeamMvalExtensions(&measurement.Val); err != nil { + log.Fatal("could not set mval extensions") + } + + refVal.Measurements.Add(measurement) + m.Triples.AddReferenceValue(*refVal) + + err := m.Valid() + if err != nil { + fmt.Printf("CoMID is not Valid :%s", err.Error()) + } + + cbor, err := m.ToCBOR() + if err == nil { + fmt.Printf("%x\n", cbor) + } else { + fmt.Printf("\n To CBOR Failed: %s \n", err.Error()) + } + + json, err := m.ToJSON() + if err == nil { + fmt.Printf("%s\n", string(json)) + } else { + fmt.Printf("\n To JSON Failed \n") + } + + // Output: + // a301a1005043bbe37f2e614b33aed353cff1428b200281a30065494e54454c01d8207168747470733a2f2f696e74656c2e636f6d028301000204a1008182a100a300d86f4c6086480186f84d01020304050171496e74656c20436f72706f726174696f6e02675444585345414d81a101a73847c11a6796cc8038480a385142010138528182015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7538538282015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d7582075830e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75e45b72f5c0c0b572db4d8d3ab7e97f36385442010138550b + // {"tag-identity":{"id":"43bbe37f-2e61-4b33-aed3-53cff1428b20"},"entities":[{"name":"INTEL","regid":"https://intel.com","roles":["creator","tagCreator","maintainer"]}],"triples":{"reference-values":[{"environment":{"class":{"id":{"type":"oid","value":"2.16.840.1.113741.1.2.3.4.5"},"vendor":"Intel Corporation","model":"TDXSEAM"}},"measurements":[{"value":{"tcbdate":"2025-01-27T00:00:00Z","isvsvn":10,"attributes":"AQE=","mrtee":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU="],"mrsigner":["sha-256;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=","sha-384;5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82"],"isvprodid":{"type":"bytes","value":"AQE="},"tcbevalnum":11}}]}]}} +} + +func setTDXSeamMvalExtensions(val *comid.Mval) error { + tcbDate, _ := time.Parse(time.RFC3339, "2025-01-27T00:00:00Z") + err := val.Extensions.Set("tcbdate", &tcbDate) + if err != nil { + return fmt.Errorf("unable to set tcbDate %w", err) + } + r := []byte{0x01, 0x01} + isvProdID := NewISVProdID(r) + err = val.Extensions.Set("isvprodid", isvProdID) + if err != nil { + return fmt.Errorf("unable to set isvprodid %w", err) + } + svn := TeeSVN(TestISVSVN) + err = val.Extensions.Set("isvsvn", &svn) + if err != nil { + return fmt.Errorf("unable to set isvsvn %w", err) + } + teeTcbEvNum := TeeTcbEvalNum(TestTCBEvalNum) + err = val.Extensions.Set("tcbevalnum", &teeTcbEvNum) + if err != nil { + return fmt.Errorf("unable to set tcbevalnum %w", err) + } + + teeAttr := NewTeeAttributes(TestTeeAttributes) + err = val.Extensions.Set("attributes", teeAttr) + if err != nil { + return fmt.Errorf("unable to set attributes %w", err) + } + + d := comid.NewDigests() + d.AddDigest(swid.Sha256, comid.MustHexDecode(nil, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75")) + err = val.Extensions.Set("mrtee", d) + if err != nil { + return fmt.Errorf("unable to set mrtee %w", err) + } + + d = comid.NewDigests() + d.AddDigest(swid.Sha256, comid.MustHexDecode(nil, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75")) + d.AddDigest(swid.Sha384, comid.MustHexDecode(nil, "e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d75e45b72f5c0c0b572db4d8d3ab7e97f36")) + + err = val.Extensions.Set("mrsigner", d) + if err != nil { + return fmt.Errorf("unable to set mrsigner %w", err) + } + return nil +} + +func decodeMValExtensions(m *comid.Measurement) error { + val, err := m.Val.Extensions.Get("tcbevalnum") + if err != nil { + return fmt.Errorf("failed to decode tcbevalnum from measurement extensions") + } + f, ok := val.(*TeeTcbEvalNum) + if !ok { + fmt.Printf("val was not pointer to TeeTcbEvalNum") + } + tcbValNum := *f + fmt.Printf("\ntcbEvalNum: %d", tcbValNum) + + val, err = m.Val.Extensions.Get("isvprodid") + if err != nil { + return fmt.Errorf("failed to decode isvprodid from measurement extensions") + } + tS, ok := val.(*TeeIsvProdID) + if !ok { + fmt.Printf("val was not pointer to IsvProdID") + } + if tS.IsBytesIsvProdID() { + val, err = tS.GetBytesIsvProdID() + if err != nil { + return fmt.Errorf("failed to decode isvprodid: %w", err) + } + fmt.Printf("\nIsvProdID: %x", val) + } else if tS.IsUintIsvProdID() { + val, err = tS.GetUintIsvProdID() + if err != nil { + return fmt.Errorf("failed to decode isvprodid: %w", err) + } + fmt.Printf("\nIsvProdID: %d", val) + } else { + return fmt.Errorf("isvprodid is neither integer or byte string") + } + + val, err = m.Val.Extensions.Get("isvsvn") + if err != nil { + return fmt.Errorf("failed to decode isvsvn from measurement extensions") + } + tSV, ok := val.(*TeeSVN) + if !ok { + fmt.Printf("val was not pointer to tee svn") + } + + fmt.Printf("\nISVSVN: %d", *tSV) + + val, err = m.Val.Extensions.Get("attributes") + if err != nil { + return fmt.Errorf("failed to decode attributes from measurement extensions") + } + + tA, ok := val.(*TeeAttributes) + if !ok { + fmt.Printf("val was not pointer to teeAttributes") + } + + fmt.Printf("\nAttributes: %x", *tA) + + val, err = m.Val.Extensions.Get("mrtee") + if err != nil { + return fmt.Errorf("failed to decode mrtee from measurement extensions") + } + + tD, ok := val.(*TeeDigest) + if !ok { + fmt.Printf("val was not pointer to TeeDigest") + } + + err = extractDigest("mrtee", tD) + if err != nil { + return fmt.Errorf("unable to extract TEE Digest: %w", err) + } + + val, err = m.Val.Extensions.Get("mrsigner") + if err != nil { + return fmt.Errorf("failed to decode mrsigner from measurement extensions") + } + + tD, ok = val.(*TeeDigest) + if !ok { + fmt.Printf("val was not pointer to TeeDigest") + } + + err = extractDigest("mrsigner", tD) + if err != nil { + return fmt.Errorf("unable to extract TEE Digest: %w", err) + } + return nil +} + +func decodeAuthorisedBy(m *comid.Measurement) error { + if err := m.AuthorizedBy.Valid(); err != nil { + return fmt.Errorf("invalid cryptokey: %w", err) + } + fmt.Printf("\nCryptoKey Type: %s", m.AuthorizedBy.Type()) + fmt.Printf("\nCryptoKey Value: %s", m.AuthorizedBy.String()) + return nil +} + +var ( + // test cases are based on diag files here: + // https://github.com/ietf-rats-wg/draft-ietf-rats-corim/tree/main/cddl/examples + + //go:embed testcases/comid_seam_refval.cbor + testComid1 []byte +) + +func Example_decode_CBOR() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + manifest, found := corim.GetProfileManifest(profileID) + if !found { + fmt.Printf("CoRIM Profile NOT FOUND") + return + } + + m := manifest.GetComid() + + if err := m.FromCBOR(testComid1); err != nil { + panic(err) + } + if err := m.Valid(); err != nil { + panic(err) + } + + if err := extractRefVals(m); err != nil { + panic(err) + } + + // output: + // OID: 2.16.840.1.113741.1.2.3.4.3 + // Vendor: Intel Corporation + // Model: TDX SEAM + // tcbEvalNum: 11 + // IsvProdID: abcd + // ISVSVN: 6 + // Attributes: 0102 + // mrtee Digest Alg: 1 + // mrtee Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // mrsigner Digest Alg: 1 + // mrsigner Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // mrsigner Digest Alg: 8 + // mrsigner Digest Value: a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6aa314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a + // CryptoKey Type: pkix-base64-key + // CryptoKey Value: -----BEGIN PUBLIC KEY----- + // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg== + // -----END PUBLIC KEY----- +} + +func extractRefVals(c *comid.Comid) error { + if c.Triples.ReferenceValues == nil { + return fmt.Errorf("no reference values triples") + } + + for i, rv := range c.Triples.ReferenceValues.Values { + if err := extractSeamRefVal(rv); err != nil { + return fmt.Errorf("bad reference value at index %d: %w", i, err) + } + } + return nil +} + +func extractSeamRefVal(rv comid.ValueTriple) error { + class := rv.Environment.Class + + if err := extractClassElements(class); err != nil { + return fmt.Errorf("extracting class: %w", err) + } + + measurements := rv.Measurements + if err := extractSeamMeasurements(&measurements); err != nil { + return fmt.Errorf("extracting measurements: %w", err) + } + + return nil +} + +func extractSeamMeasurements(meas *comid.Measurements) error { + if len(meas.Values) == 0 { + return fmt.Errorf("no measurements") + } + for i := range meas.Values { + m := &meas.Values[0] + if err := decodeMValExtensions(m); err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + + if m.AuthorizedBy != nil { + err := decodeAuthorisedBy(m) + if err != nil { + return fmt.Errorf("extracting measurement at index %d: %w", i, err) + } + } + } + return nil +} + +func extractClassElements(c *comid.Class) error { + if c == nil { + return fmt.Errorf("no class") + } + + classID := c.ClassID + + if classID == nil { + return fmt.Errorf("no class-id") + } + + if classID.Type() != comid.OIDType { + return fmt.Errorf("class id is not an oid") + } + + fmt.Printf("OID: %s", classID.Value.String()) + + if c.Vendor == nil { + return fmt.Errorf("no Vendor") + } + fmt.Printf("\nVendor: %s", *c.Vendor) + + if c.Model == nil { + return fmt.Errorf("no Model") + } + fmt.Printf("\nModel: %s", *c.Model) + + return nil +} + +func extractDigest(typ string, d *TeeDigest) error { + if d == nil { + return fmt.Errorf("no TEE digest") + } + + if typ != "mrsigner" && typ != "mrtee" { + return fmt.Errorf("invalid type for TEE digest: %s", typ) + } + for _, digest := range *d { + fmt.Printf("\n%s Digest Alg: %d", typ, digest.HashAlgID) + fmt.Printf("\n%s Digest Value: %x", typ, digest.HashValue) + } + + return nil +} diff --git a/comid/tdx-profile/mval_extensions.go b/comid/tdx-profile/mval_extensions.go new file mode 100644 index 00000000..3760a086 --- /dev/null +++ b/comid/tdx-profile/mval_extensions.go @@ -0,0 +1,55 @@ +package tdx + +import ( + "time" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" +) + +// MValExtensions contains the Intel TDX profile extensions which can appear in +// both Reference Values and Endorsed Values +type MValExtensions struct { + TcbDate *time.Time `cbor:"-72,keyasint,omitempty" json:"tcbdate,omitempty"` + IsvSVN *TeeSVN `cbor:"-73,keyasint,omitempty" json:"isvsvn,omitempty"` + InstanceID *TeeInstanceID `cbor:"-77,keyasint,omitempty" json:"instanceid,omitempty"` + PCEID *TeePCEID `cbor:"-80,keyasint,omitempty" json:"pceid,omitempty"` + MiscSelect *TeeMiscSelect `cbor:"-81,keyasint,omitempty" json:"miscselect,omitempty"` + Attributes *TeeAttributes `cbor:"-82,keyasint,omitempty" json:"attributes,omitempty"` + MrTee *TeeDigest `cbor:"-83,keyasint,omitempty" json:"mrtee,omitempty"` + MrSigner *TeeDigest `cbor:"-84,keyasint,omitempty" json:"mrsigner,omitempty"` + IsvProdID *TeeIsvProdID `cbor:"-85,keyasint,omitempty" json:"isvprodid,omitempty"` + TcbEvalNum *TeeTcbEvalNum `cbor:"-86,keyasint,omitempty" json:"tcbevalnum,omitempty"` + TcbStatus *TeeTcbStatus `cbor:"-88,keyasint,omitempty" json:"tcbstatus,omitempty"` + AdvisoryIDs *TeeAdvisoryIDs `cbor:"-89,keyasint,omitempty" json:"advisoryids,omitempty"` + Epoch *time.Time `cbor:"-90, keyasint,omitempty" json:"epoch,omitempty"` + + TeeCryptoKeys *comid.CryptoKeys `cbor:"-91, keyasint,omitempty" json:"teecryptokeys,omitempty"` + TCBCompSvn *TeeTcbCompSvn `cbor:"-125, keyasint,omitempty" json:"tcbcompsvn,omitempty"` +} + +// Registering the profile inside init() in the same file where it is defined +// ensures that the profile will always be available, and you don't need to +// remember to register it at the time you want to use it. The only potential +// danger with that is if the your profile ID clashes with another profile, +// which should not happen if it a registered PEN or a URL containing a domain +// that you own. + +func init() { + profileID, err := eat.NewProfile("http://intel.com/tdx-profile") + if err != nil { + panic(err) // will not error, as the hard-coded string above is valid + } + + extMap := extensions.NewMap(). + Add(comid.ExtReferenceValue, &MValExtensions{}). + Add(comid.ExtEndorsedValue, &MValExtensions{}) + + if err := corim.RegisterProfile(profileID, extMap); err != nil { + // will not error, assuming our profile ID is unique, and we've + // correctly set up the extensions Map above + panic(err) + } +} diff --git a/comid/tdx-profile/teeadvisoryids.go b/comid/tdx-profile/teeadvisoryids.go new file mode 100644 index 00000000..8ce5cca6 --- /dev/null +++ b/comid/tdx-profile/teeadvisoryids.go @@ -0,0 +1,51 @@ +// nolint:dupl +package tdx + +import "fmt" + +type TeeAdvisoryIDs setType + +func NewAdvisoryIDs(val []any) *TeeAdvisoryIDs { + var adv TeeAdvisoryIDs + if len(val) == 0 { + return nil + } + + for _, v := range val { + switch t := v.(type) { + case string: + adv = append(adv, t) + default: + return nil + } + } + return &adv +} + +func (o *TeeAdvisoryIDs) AddAdvisoryIDs(val []any) error { + for _, v := range val { + switch t := v.(type) { + case string: + *o = append(*o, t) + default: + return fmt.Errorf("invalid type: %T for AdvisoryIDs", t) + } + } + return nil +} + +func (o TeeAdvisoryIDs) Valid() error { + if len(o) == 0 { + return fmt.Errorf("empty AdvisoryIDs") + + } + for _, v := range o { + switch t := v.(type) { + case string: + continue + default: + return fmt.Errorf("invalid type: %T for AdvisoryIDs", t) + } + } + return nil +} diff --git a/comid/tdx-profile/teeadvisoryids_test.go b/comid/tdx-profile/teeadvisoryids_test.go new file mode 100644 index 00000000..97d40a6d --- /dev/null +++ b/comid/tdx-profile/teeadvisoryids_test.go @@ -0,0 +1,73 @@ +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func initAdvisoryIDs() []any { + s := make([]any, len(TestAdvisoryIDs)) + for i := range TestAdvisoryIDs { + s[i] = TestAdvisoryIDs[i] + } + return s +} + +func TestAdvisoryIDs_NewAdvisoryIDs_OK(t *testing.T) { + a := initAdvisoryIDs() + adv := NewAdvisoryIDs(a) + require.NotNil(t, adv) +} + +func TestAdvisoryIDs_NewAdvisoryIDs_NOK(t *testing.T) { + a := make([]any, len(TestAdvisoryIDs)) + for i := range TestAdvisoryIDs { + a[i] = i + } + adv := NewAdvisoryIDs(a) + require.Nil(t, adv) +} + +func TestAdvisoryIDs_AddAdvisoryIDs_OK(t *testing.T) { + a := initAdvisoryIDs() + adv := TeeAdvisoryIDs{} + err := adv.AddAdvisoryIDs(a) + require.NoError(t, err) +} + +func TestAdvisoryIDs_AddAdvisoryIDs_NOK(t *testing.T) { + expectedErr := "invalid type: float64 for AdvisoryIDs" + s := make([]any, len(TestInvalidAdvisoryIDs)) + for i := range TestInvalidAdvisoryIDs { + s[i] = TestInvalidAdvisoryIDs[i] + } + adv := TeeAdvisoryIDs{} + err := adv.AddAdvisoryIDs(s) + assert.EqualError(t, err, expectedErr) +} + +func TestAdvisoryIDs_Valid_OK(t *testing.T) { + a := initAdvisoryIDs() + adv := NewAdvisoryIDs(a) + err := adv.Valid() + require.NoError(t, err) +} + +func TestAdvisoryIDs_Valid_NOK(t *testing.T) { + expectedErr := "empty AdvisoryIDs" + adv := TeeAdvisoryIDs{} + err := adv.Valid() + assert.EqualError(t, err, expectedErr) + + expectedErr = "invalid type: float64 for AdvisoryIDs" + s := make([]any, len(TestInvalidAdvisoryIDs)) + for i := range TestInvalidAdvisoryIDs { + s[i] = TestInvalidAdvisoryIDs[i] + } + adv = TeeAdvisoryIDs(s) + err = adv.Valid() + assert.EqualError(t, err, expectedErr) + +} diff --git a/comid/tdx-profile/teeattributes.go b/comid/tdx-profile/teeattributes.go new file mode 100644 index 00000000..a454d86f --- /dev/null +++ b/comid/tdx-profile/teeattributes.go @@ -0,0 +1,24 @@ +// nolint:dupl +package tdx + +import "fmt" + +type TeeAttributes maskType + +func NewTeeAttributes(val []byte) *TeeAttributes { + if val == nil { + return nil + } + teeAttributes := TeeAttributes(val) + return &teeAttributes +} + +func (o TeeAttributes) Valid() error { + if o == nil { + return fmt.Errorf("nil TeeAttributes") + } + if len(o) == 0 { + return fmt.Errorf("zero len TeeAttributes") + } + return nil +} diff --git a/comid/tdx-profile/teeattributes_test.go b/comid/tdx-profile/teeattributes_test.go new file mode 100644 index 00000000..670eb767 --- /dev/null +++ b/comid/tdx-profile/teeattributes_test.go @@ -0,0 +1,31 @@ +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewTeeAttributes_NewTeeAttributes_OK(t *testing.T) { + tA := NewTeeAttributes(TestTeeAttributes) + require.NotNil(t, tA) +} + +func TestNewTeeAttributes_NewTeeAttributes_NOK(t *testing.T) { + tA := NewTeeAttributes(nil) + require.Nil(t, tA) +} + +func TestNewTeeAttributes_Valid_OK(t *testing.T) { + tA := TeeAttributes(TestTeeAttributes) + err := tA.Valid() + require.Nil(t, err) +} + +func TestNewTeeAttributes_Valid_NOK(t *testing.T) { + tA := TeeAttributes{} + expectedErr := "zero len TeeAttributes" + err := tA.Valid() + assert.EqualError(t, err, expectedErr) +} diff --git a/comid/tdx-profile/teeinstanceid.go b/comid/tdx-profile/teeinstanceid.go new file mode 100644 index 00000000..d11105a9 --- /dev/null +++ b/comid/tdx-profile/teeinstanceid.go @@ -0,0 +1,171 @@ +// nolint:dupl +package tdx + +import ( + "encoding/json" + "fmt" + + "github.com/fxamacker/cbor/v2" + "github.com/veraison/corim/encoding" +) + +// TeeInstanceID stores an TEE Instance Identifier. The supported formats are uint and variable-length bytes. +type TeeInstanceID struct { + val interface{} +} + +func NewInstanceID(val interface{}) *TeeInstanceID { + switch t := val.(type) { + case uint, uint64: + return &TeeInstanceID{val: t} + case []byte: + return &TeeInstanceID{val: t} + case int: + if t < 0 { + return nil + } + return &TeeInstanceID{val: t} + default: + return nil + } +} + +func (o *TeeInstanceID) SetInstanceID(val interface{}) error { + switch t := val.(type) { + case uint, uint64: + o.val = val + case []byte: + o.val = val + case int: + if t < 0 { + return fmt.Errorf("unsupported negative InstanceID: %d", t) + } + o.val = val + default: + return fmt.Errorf("unsupported InstanceID type: %T", t) + } + return nil +} + +func (o TeeInstanceID) Valid() error { + if o.val == nil { + return fmt.Errorf("empty InstanceID") + } + switch t := o.val.(type) { + case uint, uint64: + return nil + case []byte: + if len(t) == 0 { + return fmt.Errorf("empty InstanceID") + } + case int: + if t < 0 { + return fmt.Errorf("unsupported negative InstanceID: %d", t) + } + default: + return fmt.Errorf("unsupported InstanceID type: %T", t) + } + return nil +} + +func (o TeeInstanceID) GetUintInstanceID() (uint, error) { + switch t := o.val.(type) { + case uint64: + return uint(t), nil + case uint: + return t, nil + default: + return 0, fmt.Errorf("InstanceID type is: %T", t) + } +} + +func (o TeeInstanceID) GetBytesInstanceID() ([]byte, error) { + switch t := o.val.(type) { + case []byte: + if len(t) == 0 { + return nil, fmt.Errorf("InstanceID type is of zero length") + } + return t, nil + default: + return nil, fmt.Errorf("InstanceID type is: %T", t) + } +} +func (o TeeInstanceID) IsBytesInstanceID() bool { + switch o.val.(type) { + case []byte: + return true + default: + return false + } +} + +func (o TeeInstanceID) IsUintInstanceID() bool { + switch o.val.(type) { + case uint64, uint: + return true + default: + return false + } +} + +func (o TeeInstanceID) MarshalJSON() ([]byte, error) { + + if o.Valid() != nil { + return nil, fmt.Errorf("invalid InstanceID") + } + var ( + v encoding.TypeAndValue + b []byte + err error + ) + switch t := o.val.(type) { + case uint, uint64, int: + b, err = json.Marshal(t) + if err != nil { + return nil, err + } + v = encoding.TypeAndValue{Type: "uint", Value: b} + case []byte: + b, err = json.Marshal(t) + if err != nil { + return nil, err + } + v = encoding.TypeAndValue{Type: "bytes", Value: b} + default: + return nil, fmt.Errorf("unknown type %T for InstanceID", t) + } + return json.Marshal(v) +} + +func (o *TeeInstanceID) UnmarshalJSON(data []byte) error { + var v encoding.TypeAndValue + + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + switch v.Type { + case "uint": + var x uint + if err := json.Unmarshal(v.Value, &x); err != nil { + return fmt.Errorf( + "cannot unmarshal InstanceID of type uint: %w", err) + } + o.val = x + case "bytes": + var x []byte + if err := json.Unmarshal(v.Value, &x); err != nil { + return fmt.Errorf( + "cannot unmarshal InstanceID of type bytes: %w", err) + } + o.val = x + } + return nil +} +func (o TeeInstanceID) MarshalCBOR() ([]byte, error) { + return cbor.Marshal(o.val) +} + +func (o *TeeInstanceID) UnmarshalCBOR(data []byte) error { + return cbor.Unmarshal(data, &o.val) +} diff --git a/comid/tdx-profile/teeinstanceid_test.go b/comid/tdx-profile/teeinstanceid_test.go new file mode 100644 index 00000000..709249f0 --- /dev/null +++ b/comid/tdx-profile/teeinstanceid_test.go @@ -0,0 +1,115 @@ +package tdx + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/veraison/corim/comid" +) + +func TestInstanceID_NewInstanceID_OK(t *testing.T) { + tvs := []struct { + desc string + input interface{} + }{ + { + desc: "integer", + input: TestUIntInstance, + }, + { + desc: "byte array", + input: TestByteInstance, + }, + { + desc: "unsigned integer 64", + input: uint64(TestUIntInstance), + }, + } + + for _, tv := range tvs { + inst := NewInstanceID(tv.input) + require.NotNil(t, inst) + } +} + +func TestInstanceID_SetInstanceID_OK(t *testing.T) { + inst := &TeeInstanceID{} + err := inst.SetInstanceID(TestUIntInstance) + require.NoError(t, err) + err = inst.SetInstanceID(TestByteInstance) + require.NoError(t, err) + err = inst.SetInstanceID(uint64(1000)) + require.NoError(t, err) +} + +func TestInstanceID_SetInstanceID_NOK(t *testing.T) { + inst := &TeeInstanceID{} + expectedErr := "unsupported negative InstanceID: -1" + err := inst.SetInstanceID(-1) + assert.EqualError(t, err, expectedErr) + expectedErr = "unsupported InstanceID type: float64" + err = inst.SetInstanceID(-1.234) + assert.EqualError(t, err, expectedErr) +} + +func TestInstanceID_Valid_OK(t *testing.T) { + inst := &TeeInstanceID{TestUIntInstance} + err := inst.Valid() + require.NoError(t, err) +} + +func TestInstanceID_Valid_NOK(t *testing.T) { + tvs := []struct { + desc string + input interface{} + expectedErr string + }{ + { + desc: "unsupported type negative integer", + input: -1, + expectedErr: "unsupported negative InstanceID: -1", + }, + { + desc: "non existent InstanceID", + input: nil, + expectedErr: "empty InstanceID", + }, + { + desc: "non existent InstanceID", + input: []byte{}, + expectedErr: "empty InstanceID", + }, + { + desc: "unsupported type float64", + input: 1.234, + expectedErr: "unsupported InstanceID type: float64", + }, + } + + for _, tv := range tvs { + inst := &TeeInstanceID{tv.input} + err := inst.Valid() + assert.EqualError(t, err, tv.expectedErr) + } +} + +func TestInstanceID_MarshalCBOR_Bytes(t *testing.T) { + inst := NewInstanceID(TestByteInstance) + require.NotNil(t, inst) + expected := comid.MustHexDecode(t, "43454647") + actual, err := inst.MarshalCBOR() + fmt.Printf("CBOR: %x\n", actual) + assert.Nil(t, err) + assert.Equal(t, expected, actual) +} + +func TestInstanceID_JSON(t *testing.T) { + inst := TeeInstanceID{TestByteInstance} + ji, err := inst.MarshalJSON() + assert.Nil(t, err) + i := &TeeInstanceID{} + err = i.UnmarshalJSON(ji) + assert.Nil(t, err) +} diff --git a/comid/tdx-profile/teeisvproid.go b/comid/tdx-profile/teeisvproid.go new file mode 100644 index 00000000..fbc2155a --- /dev/null +++ b/comid/tdx-profile/teeisvproid.go @@ -0,0 +1,170 @@ +// nolint:dupl +package tdx + +import ( + "encoding/json" + "fmt" + + "github.com/fxamacker/cbor/v2" + "github.com/veraison/corim/encoding" +) + +// TeeIsvProdID stores an ISV Product Identifier. The supported formats are uint and variable-length bytes. +type TeeIsvProdID struct { + val interface{} +} + +func NewISVProdID(val interface{}) *TeeIsvProdID { + switch t := val.(type) { + case uint, uint64: + return &TeeIsvProdID{val: t} + case []byte: + return &TeeIsvProdID{val: t} + case int: + if t < 0 { + return nil + } + return &TeeIsvProdID{val: t} + default: + return nil + } +} + +func (o *TeeIsvProdID) SetISVProdID(val interface{}) error { + switch t := val.(type) { + case uint, uint64: + o.val = val + case []byte: + o.val = val + case int: + if t < 0 { + return fmt.Errorf("unsupported negative IsvProdID: %d", t) + } + o.val = val + default: + return fmt.Errorf("unsupported IsvProdID type: %T", t) + } + return nil +} + +func (o TeeIsvProdID) Valid() error { + if o.val == nil { + return fmt.Errorf("empty IsvProdID") + } + switch t := o.val.(type) { + case uint, uint64: + return nil + case []byte: + if len(t) == 0 { + return fmt.Errorf("empty IsvProdID") + } + case int: + if t < 0 { + return fmt.Errorf("unsupported negative IsvProdID: %d", t) + } + default: + return fmt.Errorf("unsupported IsvProdID type: %T", t) + } + return nil +} + +func (o TeeIsvProdID) GetUintIsvProdID() (uint, error) { + switch t := o.val.(type) { + case uint64: + return uint(t), nil + case uint: + return t, nil + default: + return 0, fmt.Errorf("IsvProdID type is: %T", t) + } +} + +func (o TeeIsvProdID) GetBytesIsvProdID() ([]byte, error) { + switch t := o.val.(type) { + case []byte: + if len(t) == 0 { + return nil, fmt.Errorf("IsvProdID type is of zero length") + } + return t, nil + default: + return nil, fmt.Errorf("IsvProdID type is: %T", t) + } +} +func (o TeeIsvProdID) IsBytesIsvProdID() bool { + switch o.val.(type) { + case []byte: + return true + default: + return false + } +} + +func (o TeeIsvProdID) IsUintIsvProdID() bool { + switch o.val.(type) { + case uint64, uint: + return true + default: + return false + } +} + +func (o TeeIsvProdID) MarshalJSON() ([]byte, error) { + if o.Valid() != nil { + return nil, fmt.Errorf("invalid IsvProdID") + } + var ( + v encoding.TypeAndValue + b []byte + err error + ) + switch t := o.val.(type) { + case uint, uint64, int: + b, err = json.Marshal(t) + if err != nil { + return nil, err + } + v = encoding.TypeAndValue{Type: "uint", Value: b} + case []byte: + b, err = json.Marshal(t) + if err != nil { + return nil, err + } + v = encoding.TypeAndValue{Type: "bytes", Value: b} + default: + return nil, fmt.Errorf("unknown type %T for IsvProdID", t) + } + return json.Marshal(v) +} + +func (o *TeeIsvProdID) UnmarshalJSON(data []byte) error { + var v encoding.TypeAndValue + + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + switch v.Type { + case "uint": + var x uint + if err := json.Unmarshal(v.Value, &x); err != nil { + return fmt.Errorf( + "cannot unmarshal IsvProdID of type uint: %w", err) + } + o.val = x + case "bytes": + var x []byte + if err := json.Unmarshal(v.Value, &x); err != nil { + return fmt.Errorf( + "cannot unmarshal IsvProdID of type bytes: %w", err) + } + o.val = x + } + return nil +} +func (o TeeIsvProdID) MarshalCBOR() ([]byte, error) { + return cbor.Marshal(o.val) +} + +func (o *TeeIsvProdID) UnmarshalCBOR(data []byte) error { + return cbor.Unmarshal(data, &o.val) +} diff --git a/comid/tdx-profile/teeisvproid_test.go b/comid/tdx-profile/teeisvproid_test.go new file mode 100644 index 00000000..f9478218 --- /dev/null +++ b/comid/tdx-profile/teeisvproid_test.go @@ -0,0 +1,118 @@ +package tdx + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/veraison/corim/comid" +) + +func TestIsvProdID_NewISVProdID_OK(t *testing.T) { + tvs := []struct { + desc string + input interface{} + }{ + { + desc: "integer", + input: TestUIntISVProdID, + }, + { + desc: "byte array", + input: TestBytesISVProdID, + }, + { + desc: "unsigned integer 64", + input: uint64(TestUIntISVProdID), + }, + } + + for _, tv := range tvs { + id := NewISVProdID(tv.input) + require.NotNil(t, id) + } +} + +func TestIsvProdID_SetIsvProdID_OK(t *testing.T) { + id := &TeeIsvProdID{} + err := id.SetISVProdID(TestUIntISVProdID) + require.NoError(t, err) + err = id.SetISVProdID(TestBytesISVProdID) + require.NoError(t, err) + err = id.SetISVProdID(uint64(1000)) + require.NoError(t, err) +} + +func TestIsvProdID_SetIsvProdID_NOK(t *testing.T) { + id := &TeeIsvProdID{} + expectedErr := "unsupported negative IsvProdID: -1" + err := id.SetISVProdID(-1) + assert.EqualError(t, err, expectedErr) + expectedErr = "unsupported IsvProdID type: float64" + err = id.SetISVProdID(-1.234) + assert.EqualError(t, err, expectedErr) +} + +func TestIsvProdID_Valid_OK(t *testing.T) { + id := &TeeIsvProdID{TestUIntISVProdID} + err := id.Valid() + require.NoError(t, err) + id = &TeeIsvProdID{TestBytesISVProdID} + err = id.Valid() + require.NoError(t, err) +} + +func TestIsvProdID_Valid_NOK(t *testing.T) { + tvs := []struct { + desc string + input interface{} + expectedErr string + }{ + { + desc: "unsupported type negative integer", + input: -1, + expectedErr: "unsupported negative IsvProdID: -1", + }, + { + desc: "non existent IsvProdID", + input: nil, + expectedErr: "empty IsvProdID", + }, + { + desc: "non existent IsvProdID", + input: []byte{}, + expectedErr: "empty IsvProdID", + }, + { + desc: "unsupported type float64", + input: 1.234, + expectedErr: "unsupported IsvProdID type: float64", + }, + } + + for _, tv := range tvs { + id := &TeeIsvProdID{tv.input} + err := id.Valid() + assert.EqualError(t, err, tv.expectedErr) + } +} + +func TestIsvProdID_MarshalCBOR_Bytes(t *testing.T) { + id := NewISVProdID(TestBytesISVProdID) + require.NotNil(t, id) + expected := comid.MustHexDecode(t, "43010203") + actual, err := id.MarshalCBOR() + fmt.Printf("CBOR: %x\n", actual) + assert.Nil(t, err) + assert.Equal(t, expected, actual) +} + +func TestIsvProdID_JSON(t *testing.T) { + isv := TeeIsvProdID{TestBytesISVProdID} + jisv, err := isv.MarshalJSON() + assert.Nil(t, err) + i := &TeeIsvProdID{} + err = i.UnmarshalJSON(jisv) + assert.Nil(t, err) +} diff --git a/comid/tdx-profile/teemiscselect.go b/comid/tdx-profile/teemiscselect.go new file mode 100644 index 00000000..2ca50b0b --- /dev/null +++ b/comid/tdx-profile/teemiscselect.go @@ -0,0 +1,24 @@ +package tdx + +import "fmt" + +type TeeMiscSelect maskType + +func NewTeeMiscSelect(val []byte) *TeeMiscSelect { + var miscSelect TeeMiscSelect + if val == nil { + return nil + } + miscSelect = TeeMiscSelect(val) + return &miscSelect +} + +func (o TeeMiscSelect) Valid() error { + if o == nil { + return fmt.Errorf("nil TeeMiscSelect") + } + if len(o) == 0 { + return fmt.Errorf("zero len TeeMiscSelect") + } + return nil +} diff --git a/comid/tdx-profile/teemiscselect_test.go b/comid/tdx-profile/teemiscselect_test.go new file mode 100644 index 00000000..7abbc82c --- /dev/null +++ b/comid/tdx-profile/teemiscselect_test.go @@ -0,0 +1,31 @@ +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTeeMiscSelect_NewTeeMiscSelect_OK(t *testing.T) { + tA := NewTeeMiscSelect(TestTeeMiscSelect) + require.NotNil(t, tA) +} + +func TestTeeMiscSelect_NewTeeMiscSelect_NOK(t *testing.T) { + tA := NewTeeMiscSelect(nil) + require.Nil(t, tA) +} + +func TestNewTeeMiscSelect_Valid_OK(t *testing.T) { + tA := TeeMiscSelect(TestTeeMiscSelect) + err := tA.Valid() + require.Nil(t, err) +} + +func TestTeeMiscSelect_Valid_NOK(t *testing.T) { + tA := TeeMiscSelect{} + expectedErr := "zero len TeeMiscSelect" + err := tA.Valid() + assert.EqualError(t, err, expectedErr) +} diff --git a/comid/tdx-profile/teepceid.go b/comid/tdx-profile/teepceid.go new file mode 100644 index 00000000..4c718015 --- /dev/null +++ b/comid/tdx-profile/teepceid.go @@ -0,0 +1,23 @@ +package tdx + +import ( + "fmt" +) + +type TeePCEID string + +func NewPCEID(val string) *TeePCEID { + var pceID TeePCEID + if val == "" { + return nil + } + pceID = TeePCEID(val) + return &pceID +} + +func (o TeePCEID) Valid() error { + if o == "" { + return fmt.Errorf("nil TeePCEID") + } + return nil +} diff --git a/comid/tdx-profile/teepceid_test.go b/comid/tdx-profile/teepceid_test.go new file mode 100644 index 00000000..09add279 --- /dev/null +++ b/comid/tdx-profile/teepceid_test.go @@ -0,0 +1,31 @@ +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPCEID_NewPCEID_OK(t *testing.T) { + pceID := NewPCEID(TestPCEID) + require.NotNil(t, pceID) +} + +func TestPCEID_NewPCEID_NOK(t *testing.T) { + pceID := NewPCEID("") + require.Nil(t, pceID) +} + +func TestPCEID_Valid_OK(t *testing.T) { + pceID := NewPCEID(TestPCEID) + err := pceID.Valid() + require.Nil(t, err) +} + +func TestPCEID_Valid_NOK(t *testing.T) { + pceID := TeePCEID("") + expectedErr := "nil TeePCEID" + err := pceID.Valid() + assert.EqualError(t, err, expectedErr) +} diff --git a/comid/tdx-profile/teetcbcompsvn.go b/comid/tdx-profile/teetcbcompsvn.go new file mode 100644 index 00000000..ac8177cc --- /dev/null +++ b/comid/tdx-profile/teetcbcompsvn.go @@ -0,0 +1,29 @@ +package tdx + +import "fmt" + +const MaxSVNCount = 16 + +type TeeTcbCompSvn [MaxSVNCount]TeeSVN + +func NewTeeTcbCompSVN(val []uint) *TeeTcbCompSvn { + if len(val) > MaxSVNCount || len(val) == 0 { + return nil + } + TeeTcbCompSVN := make([]TeeSVN, MaxSVNCount) + for i, value := range val { + TeeTcbCompSVN[i] = TeeSVN(value) + } + return (*TeeTcbCompSvn)(TeeTcbCompSVN) +} + +// nolint:gocritic +func (o TeeTcbCompSvn) Valid() error { + if len(o) == 0 { + return fmt.Errorf("empty TeeTcbCompSVN") + } + if len(o) > MaxSVNCount { + return fmt.Errorf("invalid length: %d for TeeTcbCompSVN", len(o)) + } + return nil +} diff --git a/comid/tdx-profile/teetcbstatus.go b/comid/tdx-profile/teetcbstatus.go new file mode 100644 index 00000000..ffcbfe46 --- /dev/null +++ b/comid/tdx-profile/teetcbstatus.go @@ -0,0 +1,51 @@ +// nolint:dupl +package tdx + +import "fmt" + +type TeeTcbStatus setType + +func NewTeeTcbStatus(val []any) *TeeTcbStatus { + var ts TeeTcbStatus + if len(val) == 0 { + return nil + } + + for _, v := range val { + switch t := v.(type) { + case string: + ts = append(ts, t) + default: + return nil + } + } + return &ts +} + +func (o *TeeTcbStatus) AddTcbStatus(val []any) error { + for _, v := range val { + switch t := v.(type) { + case string: + *o = append(*o, t) + default: + return fmt.Errorf("invalid type: %T for tcb status", t) + } + } + return nil +} + +func (o TeeTcbStatus) Valid() error { + if len(o) == 0 { + return fmt.Errorf("empty tcb status") + } + + for _, v := range o { + switch t := v.(type) { + case string: + continue + default: + return fmt.Errorf("invalid type %T for tcb status", t) + } + } + return nil +} diff --git a/comid/tdx-profile/teetcbstatus_test.go b/comid/tdx-profile/teetcbstatus_test.go new file mode 100644 index 00000000..705fe563 --- /dev/null +++ b/comid/tdx-profile/teetcbstatus_test.go @@ -0,0 +1,74 @@ +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func initTcbStatus() []any { + s := make([]any, len(TestTCBStatus)) + for i := range TestTCBStatus { + s[i] = TestTCBStatus[i] + } + return s +} + +func TestTcbStatus_NewTeeTcbStatus_OK(t *testing.T) { + s := initTcbStatus() + status := NewTeeTcbStatus(s) + require.NotNil(t, status) +} + +func TestTcbStatus_NewTeeTcbStatus_NOK(t *testing.T) { + s := make([]any, len(TestTCBStatus)) + for i := range TestTCBStatus { + s[i] = i + } + status := NewTeeTcbStatus(s) + require.Nil(t, status) + var m []any + status = NewTeeTcbStatus(m) + require.Nil(t, status) +} + +func TestTcbStatus_AddTcbStatus_OK(t *testing.T) { + s := initTcbStatus() + status := TeeTcbStatus{} + err := status.AddTcbStatus(s) + require.Nil(t, err) +} + +func TestTcbStatus_AddTcbStatus_NOK(t *testing.T) { + expectedErr := "invalid type: int for tcb status" + s := make([]any, len(TestInvalidTCBStatus)) + for i := range TestInvalidTCBStatus { + s[i] = TestInvalidTCBStatus[i] + } + status := TeeTcbStatus{} + err := status.AddTcbStatus(s) + assert.EqualError(t, err, expectedErr) +} + +func TestTcbStatus_Valid_OK(t *testing.T) { + s := initTcbStatus() + status := NewTeeTcbStatus(s) + err := status.Valid() + require.Nil(t, err) +} + +func TestTcbStatus_Valid_NOK(t *testing.T) { + expectedErr := "empty tcb status" + status := TeeTcbStatus{} + err := status.Valid() + assert.EqualError(t, err, expectedErr) + expectedErr = "invalid type int for tcb status" + s := make([]any, len(TestInvalidTCBStatus)) + for i := range TestInvalidTCBStatus { + s[i] = TestInvalidTCBStatus[i] + } + status = TeeTcbStatus(s) + err = status.Valid() + assert.EqualError(t, err, expectedErr) +} diff --git a/comid/tdx-profile/test_vars.go b/comid/tdx-profile/test_vars.go new file mode 100644 index 00000000..7009302b --- /dev/null +++ b/comid/tdx-profile/test_vars.go @@ -0,0 +1,187 @@ +package tdx + +//nolint:lll +var ( + TestRegID = "https://intel.com" + TestOID = "2.16.840.1.113741.1.2.3.4.5" + TestUIntInstance = 45 + TestByteInstance = []byte{0x45, 0x46, 0x47} + TestInvalidProdID = -23 + TestUIntISVProdID = 23 + TestBytesISVProdID = []byte{0x01, 0x02, 0x03} + TestInvalidInstance = -1 + TestTeeAttributes = []byte{0x01, 0x01} + TestTeeMiscSelect = []byte{0x0B, 0x0C, 0x0D} + TestPCEID = "PCEID001" + TestCompSVN = []uint{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + TestTCBStatus = []string{"OutOfDate", "ConfigurationNeeded", "UpToDate"} + TestInvalidTCBStatus = []int{1, 2, 3} + TestAdvisoryIDs = []string{"SA-00078", "SA-00077", "SA-00079"} + TestInvalidAdvisoryIDs = []float64{1.234, 2.567} + TestISVSVN = 10 + TestTCBEvalNum = 11 + TestTime = "2025-01-29T00:00:00Z" + TDXPCERefValTemplate = `{ + "lang": "en-GB", + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B17", + "version": 0 + }, + "entities": [ + { + "name": "INTEL", + "regid": "https://intel.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "oid", + "value": "2.16.840.1.113741.1.2.3.4.6" + }, + "vendor": "Intel Corporation", + "model": "0123456789ABCDEF" + } + }, + "measurements": [ + { + "value": { + "instanceid": { + "type": "uint", + "value": 11 + }, + "tcbcompsvn": [10, 10, 2, 2, 2, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "pceid": "0000" + }, + "authorized-by": { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" + } + } + ] + } + ] + } +} +` + TDXQERefValTemplate = `{ + "lang": "en-GB", + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "entities": [ + { + "name": "INTEL", + "regid": "https://intel.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "oid", + "value": "2.16.840.1.113741.1.2.3.4.1" + }, + "vendor": "Intel Corporation", + "model": "TDX QE TCB" + } + }, + "measurements": [ + { + "value": { + "miscselect": "wAAAAPv/AAA=", + "tcbevalnum": 11, + "mrsigner": [ + "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", + "sha-512:oxT8LcZjrnpra8Z4dZQFc5bms/VpzVD9XdtNG7r9K2qjFPwtxmOuemtrxnh1lAVzluaz9WnNUP1d200buv0rag==" + ], + "isvprodid": { + "type": "bytes", + "value": "AwM=" + } + }, + "authorized-by": { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" + } + } + ] + } + ] + } +} +` + TDXSeamRefValJSONTemplate = `{ + "lang": "en-GB", + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B20", + "version": 0 + }, + "entities": [ + { + "name": "INTEL", + "regid": "https://intel.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "oid", + "value": "2.16.840.1.113741.1.2.3.4.5" + }, + "vendor": "Intel Corporation", + "model": "TDX SEAM" + } + }, + "measurements": [ + { + "value": { + "isvprodid": { + "type": "bytes", + "value": "AwM=" + }, + "isvsvn": 10, + "attributes": "8AoL", + "tcbevalnum": 11, + "mrtee" : ["sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc="], + "mrsigner": [ + "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", + "sha-512:oxT8LcZjrnpra8Z4dZQFc5bms/VpzVD9XdtNG7r9K2qjFPwtxmOuemtrxnh1lAVzluaz9WnNUP1d200buv0rag==" + ] + }, + "authorized-by": { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" + } + } + ] + } + ] + } +} +` +) diff --git a/comid/tdx-profile/testcases/comid_pce_refval.cbor b/comid/tdx-profile/testcases/comid_pce_refval.cbor new file mode 100644 index 0000000000000000000000000000000000000000..f0b8c0621d0c59791e1bd0422dc0fde020c5f4b9 GIT binary patch literal 382 zcmZ9Gy-vbV0EOEtF5P^C8%K@Oq~S*shW=cn(n67fmdRRf>$SAEluC(l!GSosI$}2` zcVEE=z`<8=c2gj__)RA#Cplln&Y4N6Z3oc+LnEeRG9ol2p$BCgC&VR=oh%E8LT6x) zF^sW`V;njdCbkEr8H3e^i8OWrhnGnbjSlm95+-=C@6Z5DncSS2-p!eeSy1hKR%2&h zItw;(o9s|st)NWfh{o#+;G4=BG-L!#S(-kvSy?lft!+W+xas}l^XuEk=Xd$`f#U!G zY>xS(-0bs9z&qHPyzH%z(2?4JMn}?A8P<`tE;+sGrzo{*b=p&Ju6S8&S?X_A#FnG9 zJP}nxKC!8oo(M(|*L_P%#F279`9i&|7lRAWZOC49t?^#58<{n~Hz*0IUyzgu?Uusb fCdQa2>d-$GYI@HUkV!&v-1jOKZmobC%73dLTa$R_ literal 0 HcmV?d00001 diff --git a/comid/tdx-profile/testcases/comid_qe_refval.cbor b/comid/tdx-profile/testcases/comid_qe_refval.cbor new file mode 100644 index 0000000000000000000000000000000000000000..10eafdfadeb51f0bc47b5ddd06cb98894b39a3e2 GIT binary patch literal 432 zcmZ3?xR9YjIyf=6ASYEJ*gZla&{d%*H7&I$H7_|;p(HV#sc|tws;6Iws}JK1g~E)I zl7eC@ef`Y5lGGf%&OTOA zI)$}(+Oy4HGtUP6jlJzFz3Z=bRue~r10gkp8wlSK^@7FH1AksXy|Zd{&i>f}<9A7-AX?Vp;O jYLMw!m>q8H;TsiV>>84pm+6&~Zfna0c7m&)3%aWS^`4y; literal 0 HcmV?d00001 diff --git a/comid/tdx-profile/testcases/comid_seam_refval.cbor b/comid/tdx-profile/testcases/comid_seam_refval.cbor new file mode 100644 index 0000000000000000000000000000000000000000..71e9618a33a5503e7c59b15d63f17ebfa8da3934 GIT binary patch literal 456 zcmZ3?xR4>ho^5^dN*lo^)2A~8giR>7XKGx`km~6d;_AbAL!mIEq@NvmRmE(kcex_kO51cW;IcseV1 zyGDWqxqRKS%U#POJ-qXyJgc${oE-xrJ)vwD$G~Klz;s7fw>*QA#C*r{Amf1CBJb=- zpAyGn7t4GDQ}1A3v)rWgG(YF`f>IxYbhEI65RdGr9CPFHY*Qzfiu^G1JZ=Bf)Kr5^ h&%*3*V-Me`5M$Sn%)CsmlyqBLF0d0^{anyp1pwretXu#9 literal 0 HcmV?d00001 diff --git a/comid/tdx-profile/testcases/regen-from-src.sh b/comid/tdx-profile/testcases/regen-from-src.sh new file mode 100755 index 00000000..8b9bb4d1 --- /dev/null +++ b/comid/tdx-profile/testcases/regen-from-src.sh @@ -0,0 +1,21 @@ +#!/usr/bin/bash +# Copyright 2024 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -e + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +if [[ "$(type -p diag2cbor.rb)" == "" ]]; then + echo "ERROR: please install ruby-cbor-diag package" + exit 1 +fi + +for case in "$THIS_DIR"/src/*.diag; do + outfile=$(basename "${case%%.diag}").cbor + + echo "generating $outfile" + + diag2cbor.rb "$case" > "$THIS_DIR/$outfile" +done + +echo "done." diff --git a/comid/tdx-profile/testcases/src/comid_pce_refval.diag b/comid/tdx-profile/testcases/src/comid_pce_refval.diag new file mode 100644 index 00000000..e40b8bd7 --- /dev/null +++ b/comid/tdx-profile/testcases/src/comid_pce_refval.diag @@ -0,0 +1,34 @@ +/ concise-mid-tag / { + / comid.tag-identity / 1 : { + / comid.tag-id / 0 : "Sample Provisioning Certification Enclave reference tag" + }, + / comid.entity / 2 : [ { + / comid.entity-name / 0 : "INTEL", + / comid.reg-id / 1 : 32("https://intel.com"), + / comid.role / 2 : [ 0 ] / tag-creator / + } ], + / comid.triples / 4 : { + / comid.reference-triples / 0 : [ [ + / environment-map / { + / comid.class / 0 : { + / comid.class-id / 0 : + / tagged-oid-type / 111( + h'6086480186F84D0102030405' / 2.16.840.1.113741.1.2.3.4.5 - / + ), + / comid.vendor / 1 : "Intel Corporation", + / comid.model / 2 : "TDX PCE TCB" + } + }, + [ + / measurement-map / { + / comid.mval / 1 : { + / comid.instanceid / -77 : h'00112233445566778899aabbccddeeff', + / tcb-comp-svn / -125 : [ 10, 10, 2, 2, 2, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + / pceid / -80 : "0000" + }, + / authorized-by / 2: 554("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----") + } + ] + ] ] + } +} \ No newline at end of file diff --git a/comid/tdx-profile/testcases/src/comid_qe_refval.diag b/comid/tdx-profile/testcases/src/comid_qe_refval.diag new file mode 100644 index 00000000..bf060279 --- /dev/null +++ b/comid/tdx-profile/testcases/src/comid_qe_refval.diag @@ -0,0 +1,44 @@ +/ concise-mid-tag / { + / comid.tag-identity / 1 : { + / comid.tag-id / 0 : "Sample SGX QE reference tag" + }, + / comid.entity / 2 : [ { + / comid.entity-name / 0 : "INTEL", + / comid.reg-id / 1 : 32("https://intel.com"), + / comid.role / 2 : [ 0 ] / tag-creator / + } ], + / comid.triples / 4 : { + / comid.reference-triples / 0 : [ [ + / environment-map / { + / comid.class / 0 : { + / comid.class-id / 0 : + / tagged-oid-type / 111( + h'6086480186F84D0102030401' / 2.16.840.1.113741.1.2.3.4.1 - / + ), + / comid.vendor / 1 : "Intel Corporation", + / comid.model / 2 : "SGX QE TCB" + } + }, + [ + / measurement-map / { + / comid.mval / 1 : { + / comid.miscselect / -81 :h'A0B0C0D000000000', + / comid.isvprodid / -85 : 1, + / comid.mrsigner / -84 : [ + [ + / alg-id / 1, / sha256 / + / digest / h'A314FC2DC663AE7A6B6BC6787594057396E6B3F569CD50FD5DDB4D1BBAFD2B6A' + ], + [ + / alg-id / 8, / sha384 / + / digest / h'a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6aa314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a' + ] + ], + /comid.tcbevalnum / -86 : 11 + }, + / authorized-by / 2: 554("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----") + } + ] + ] ] + } +} \ No newline at end of file diff --git a/comid/tdx-profile/testcases/src/comid_seam_refval.diag b/comid/tdx-profile/testcases/src/comid_seam_refval.diag new file mode 100644 index 00000000..32cfe5cc --- /dev/null +++ b/comid/tdx-profile/testcases/src/comid_seam_refval.diag @@ -0,0 +1,51 @@ +/ concise-mid-tag / { + / comid.tag-identity / 1 : { + / comid.tag-id / 0 : h'3f06af63a93c11e4979700505690773f' + }, + / comid.entity / 2 : [ { + / comid.entity-name / 0 : "INTEL", + / comid.reg-id / 1 : 32("https://intel.com"), + / comid.role / 2 : [ 0 ] / tag-creator / + } ], + / comid.triples / 4 : { + / comid.reference-triples / 0 : [ [ + / environment-map / { + / comid.class / 0 : { + / comid.class-id / 0 : + / tagged-oid-type / 111( + h'6086480186F84D0102030403' + ), + / comid.vendor / 1 : "Intel Corporation", + / comid.model / 2 : "TDX SEAM" + } + }, + [ + / measurement-map / { + / comid.mval / 1 : { + / comid.attributes / -82 :[ 1, 2], + / comid.isvprodid / -85 : h'ABCD', + / comid.isvsvn / -73 : 6, + / comid.mrtee / -83 : [ + [ + / alg-id / 1, / sha256 / + / digest / h'A314FC2DC663AE7A6B6BC6787594057396E6B3F569CD50FD5DDB4D1BBAFD2B6A' + ] + ], + / comid.mrsigner / -84 : [ + [ + / alg-id / 1, / sha256 / + / digest / h'A314FC2DC663AE7A6B6BC6787594057396E6B3F569CD50FD5DDB4D1BBAFD2B6A' + ], + [ + / alg-id / 8, / sha384 / + / digest / h'a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6aa314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a' + ] + ], + /comid.tcbevalnum / -86 : 11 + }, + 2: 554("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----") + } + ] + ] ] + } +} \ No newline at end of file diff --git a/comid/tdx-profile/types.go b/comid/tdx-profile/types.go new file mode 100644 index 00000000..eaf91446 --- /dev/null +++ b/comid/tdx-profile/types.go @@ -0,0 +1,11 @@ +package tdx + +import "github.com/veraison/corim/comid" + +type setType []any + +type maskType []byte +type TeeSVN uint +type TeeDigest comid.Digests + +type TeeTcbEvalNum uint diff --git a/comid/test_vars.go b/comid/test_vars.go index 5474da06..49de3ba6 100644 --- a/comid/test_vars.go +++ b/comid/test_vars.go @@ -37,6 +37,7 @@ var ( TestMKey uint64 = 700 TestCCALabel = "cca-platform-config" + //nolint:gosec TestECPrivKey = `-----BEGIN EC PRIVATE KEY----- MHcCAQEEICAm3+mCCDTMuzKqfZso9NT8ur9U9GjuUQ/lNEJvwRFMoAoGCCqGSM49 AwEHoUQDQgAEW1BvqF+/ry8BWa7ZEMU1xYYHEQ8BlLT4MFHOaO+ICTtIvrEeEpr/ diff --git a/comid/triples.go b/comid/triples.go index 7348dace..a937b7ef 100644 --- a/comid/triples.go +++ b/comid/triples.go @@ -64,7 +64,7 @@ func (o *Triples) RegisterExtensions(exts extensions.Map) error { return nil } -// GetExtensions returns pervisouosly registered extension +// GetExtensions returns previously registered extension func (o *Triples) GetExtensions() extensions.IMapValue { return o.Extensions.IMapValue }