diff --git a/comid/digests_test.go b/comid/digests_test.go index ff14b35..663a064 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/tdx-profile/common.go b/comid/tdx-profile/common.go new file mode 100644 index 0000000..032915a --- /dev/null +++ b/comid/tdx-profile/common.go @@ -0,0 +1,9 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +func isType[T any](v any) bool { + _, ok := v.(T) + return ok +} 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 0000000..36568a3 --- /dev/null +++ b/comid/tdx-profile/example_pce_refval_test.go @@ -0,0 +1,339 @@ +// Copyright 2025 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("2.16.840.1.113741.1.16.1") + 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.IsBytes() { + val, err = i.GetBytes() + if err != nil { + return fmt.Errorf("failed to decode teeinstanceid: %w", err) + } + fmt.Printf("\nInstanceID: %x", val) + } else if i.IsUint() { + val, err = i.GetUint() + if err != nil { + return fmt.Errorf("failed to decode teeinstanceid: %w", err) + } + fmt.Printf("\nInstanceID: %d", val) + } else { + return fmt.Errorf("teeinstanceid is neither integer or byte string") + } + + val, err = m.Val.Extensions.Get("tcbcompsvn") + if err != nil { + return fmt.Errorf("failed to decode teetcbcompsvn from measurement extensions") + } + + tD, ok := val.(*TeeTcbCompSvn) + if !ok { + fmt.Printf("val was not pointer to teetcbcompsvn") + } + 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("2.16.840.1.113741.1.16.1") + 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("2.16.840.1.113741.1.16.1") + 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, err := NewTeeInstanceID(TestUIntInstance) + if err != nil { + return fmt.Errorf("unable to get teeinstanceID %w", err) + } + err = val.Extensions.Set("instanceid", instanceID) + if err != nil { + return fmt.Errorf("unable to set teeinstanceID %w", err) + } + + p, err := NewTeePCEID(TestPCEID) + if err != nil { + return fmt.Errorf("unable to get NewTeepceID %w", err) + } + err = val.Extensions.Set("pceid", p) + if err != nil { + return fmt.Errorf("unable to set teepceID %w", err) + } + + c, err := NewTeeTcbCompSVN(TestCompSVN) + if err != nil { + return fmt.Errorf("failed to get TeeTcbCompSVN %w", err) + } + + err = val.Extensions.Set("tcbcompsvn", c) + if err != nil { + return fmt.Errorf("unable to set teetcbcompsvn: %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 0000000..500ab93 --- /dev/null +++ b/comid/tdx-profile/example_qe_refval_test.go @@ -0,0 +1,307 @@ +// Copyright 2025 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("2.16.840.1.113741.1.16.1") + 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.IsBytes() { + val, err = tS.GetBytes() + if err != nil { + return fmt.Errorf("failed to decode isvprodid: %w", err) + } + fmt.Printf("\nIsvProdID: %x", val) + } else if tS.IsUint() { + val, err = tS.GetUint() + 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, err := NewTeeISVProdID(r) + if err != nil { + return fmt.Errorf("unable to get isvprodid %w", err) + } + + 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("2.16.840.1.113741.1.16.1") + 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 0000000..9898b7a --- /dev/null +++ b/comid/tdx-profile/example_seam_refval_test.go @@ -0,0 +1,516 @@ +// Copyright 2025 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("2.16.840.1.113741.1.16.1") + 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("2.16.840.1.113741.1.16.1") + 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, err := NewTeeISVProdID(r) + if err != nil { + return fmt.Errorf("unable to get isvprodid %w", err) + } + 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, err := NewTeeAttributes(TestTeeAttributes) + if err != nil { + return fmt.Errorf("unable to get teeAttributes %w", err) + } + 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.IsBytes() { + val, err = tS.GetBytes() + if err != nil { + return fmt.Errorf("failed to decode isvprodid: %w", err) + } + fmt.Printf("\nIsvProdID: %x", val) + } else if tS.IsUint() { + val, err = tS.GetUint() + 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("2.16.840.1.113741.1.16.1") + 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 0000000..af4e0f2 --- /dev/null +++ b/comid/tdx-profile/mval_extensions.go @@ -0,0 +1,60 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +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 { + TeeTcbDate *time.Time `cbor:"-72,keyasint,omitempty" json:"tcbdate,omitempty"` + TeeISVSVN *TeeSVN `cbor:"-73,keyasint,omitempty" json:"isvsvn,omitempty"` + TeeInstanceID *TeeInstanceID `cbor:"-77,keyasint,omitempty" json:"instanceid,omitempty"` + TeePCEID *TeePCEID `cbor:"-80,keyasint,omitempty" json:"pceid,omitempty"` + TeeMiscSelect *TeeMiscSelect `cbor:"-81,keyasint,omitempty" json:"miscselect,omitempty"` + TeeAttributes *TeeAttributes `cbor:"-82,keyasint,omitempty" json:"attributes,omitempty"` + TeeMrTee *TeeDigest `cbor:"-83,keyasint,omitempty" json:"mrtee,omitempty"` + TeeMrSigner *TeeDigest `cbor:"-84,keyasint,omitempty" json:"mrsigner,omitempty"` + TeeISVProdID *TeeISVProdID `cbor:"-85,keyasint,omitempty" json:"isvprodid,omitempty"` + TeeTcbEvalNum *TeeTcbEvalNum `cbor:"-86,keyasint,omitempty" json:"tcbevalnum,omitempty"` + TeeTcbStatus *TeeTcbStatus `cbor:"-88,keyasint,omitempty" json:"tcbstatus,omitempty"` + TeeAdvisoryIDs *TeeAdvisoryIDs `cbor:"-89,keyasint,omitempty" json:"advisoryids,omitempty"` + TeeEpoch *time.Time `cbor:"-90, keyasint,omitempty" json:"epoch,omitempty"` + + TeeCryptoKeys *comid.CryptoKeys `cbor:"-91, keyasint,omitempty" json:"teecryptokeys,omitempty"` + TeeTCBCompSvn *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 when you want to use it. The only potential +// danger with that is if your profile ID clashes with another profile, +// which should not happen if it is a registered PEN or a URL containing a domain +// that you own. +// Note Intel profile is "2.16.840.1.113741.1.16.1", +// which is "joint-iso-itu-t.country.us.organization.intel.intel-comid.profile" + +func init() { + profileID, err := eat.NewProfile("2.16.840.1.113741.1.16.1") + 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 0000000..7662e79 --- /dev/null +++ b/comid/tdx-profile/teeadvisoryids.go @@ -0,0 +1,61 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +// nolint:dupl +package tdx + +import "fmt" + +type TeeAdvisoryIDs setType + +// NewTeeAvisoryIDs create a new TeeAvisoryIDs from the +// supplied interface array and returns a pointer to +// the AdvisoryIDs. Only +// Advisory IDs of string type are supported +func NewTeeAvisoryIDs(val []any) (*TeeAdvisoryIDs, error) { + var adv TeeAdvisoryIDs + if len(val) == 0 { + return nil, fmt.Errorf("zero len TeeAdvisoryIDs") + } + + for i, v := range val { + switch t := v.(type) { + case string: + adv = append(adv, t) + default: + return nil, fmt.Errorf("invalid type: %T for AdvisoryIDs at index: %d", t, i) + } + } + return &adv, nil +} + +// AddTeeAdvisoryIDs add supplied AvisoryIDs to existing AdvisoryIDs +func (o *TeeAdvisoryIDs) AddTeeAdvisoryIDs(val []any) error { + for i, v := range val { + switch t := v.(type) { + case string: + *o = append(*o, t) + default: + return fmt.Errorf("invalid type: %T for AdvisoryIDs at index: %d", t, i) + } + } + return nil +} + +// Valid checks for validity of TeeAdvisoryIDs and +// returns an error, if invalid +func (o TeeAdvisoryIDs) Valid() error { + if len(o) == 0 { + return fmt.Errorf("empty AdvisoryIDs") + + } + for i, v := range o { + switch t := v.(type) { + case string: + continue + default: + return fmt.Errorf("invalid type: %T for AdvisoryIDs at index: %d", t, i) + } + } + return nil +} diff --git a/comid/tdx-profile/teeadvisoryids_test.go b/comid/tdx-profile/teeadvisoryids_test.go new file mode 100644 index 0000000..0178598 --- /dev/null +++ b/comid/tdx-profile/teeadvisoryids_test.go @@ -0,0 +1,78 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +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_NewTeeAvisoryIDs_OK(t *testing.T) { + a := initAdvisoryIDs() + _, err := NewTeeAvisoryIDs(a) + require.Nil(t, err) +} + +func TestAdvisoryIDs_NewTeeAvisoryIDs_NOK(t *testing.T) { + expectedErr := "invalid type: int for AdvisoryIDs at index: 0" + a := make([]any, len(TestAdvisoryIDs)) + for i := range TestAdvisoryIDs { + a[i] = i + } + _, err := NewTeeAvisoryIDs(a) + assert.EqualError(t, err, expectedErr) +} + +func TestAdvisoryIDs_AddAdvisoryIDs_OK(t *testing.T) { + a := initAdvisoryIDs() + adv := TeeAdvisoryIDs{} + err := adv.AddTeeAdvisoryIDs(a) + require.NoError(t, err) +} + +func TestAdvisoryIDs_AddAdvisoryIDs_NOK(t *testing.T) { + expectedErr := "invalid type: float64 for AdvisoryIDs at index: 0" + s := make([]any, len(TestInvalidAdvisoryIDs)) + for i := range TestInvalidAdvisoryIDs { + s[i] = TestInvalidAdvisoryIDs[i] + } + adv := TeeAdvisoryIDs{} + err := adv.AddTeeAdvisoryIDs(s) + assert.EqualError(t, err, expectedErr) +} + +func TestAdvisoryIDs_Valid_OK(t *testing.T) { + a := initAdvisoryIDs() + adv, err := NewTeeAvisoryIDs(a) + require.NoError(t, err) + 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 at index: 0" + 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 0000000..64cdd0f --- /dev/null +++ b/comid/tdx-profile/teeattributes.go @@ -0,0 +1,27 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +// nolint:dupl +package tdx + +import "fmt" + +type TeeAttributes maskType + +func NewTeeAttributes(val []byte) (*TeeAttributes, error) { + if val == nil { + return nil, fmt.Errorf("nil TeeAttributes") + } + teeAttributes := TeeAttributes(val) + return &teeAttributes, nil +} + +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 0000000..c5734f2 --- /dev/null +++ b/comid/tdx-profile/teeattributes_test.go @@ -0,0 +1,35 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewTeeAttributes_NewTeeAttributes_OK(t *testing.T) { + _, err := NewTeeAttributes(TestTeeAttributes) + require.Nil(t, err) +} + +func TestNewTeeAttributes_NewTeeAttributes_NOK(t *testing.T) { + expectedErr := "nil TeeAttributes" + _, err := NewTeeAttributes(nil) + assert.EqualError(t, err, expectedErr) +} + +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 0000000..8d9cbae --- /dev/null +++ b/comid/tdx-profile/teeinstanceid.go @@ -0,0 +1,179 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +// 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{} +} + +// NewTeeInstanceID creates a new InstanceID from the +// supplied interface. The supported types are positive integers and +// byte array +func NewTeeInstanceID(val any) (*TeeInstanceID, error) { + switch t := val.(type) { + case uint, uint64: + return &TeeInstanceID{val: t}, nil + case []byte: + return &TeeInstanceID{val: t}, nil + case int: + if t < 0 { + return nil, fmt.Errorf("unsupported negative %d TeeInstanceID", t) + } + return &TeeInstanceID{val: t}, nil + default: + return nil, fmt.Errorf("unsupported TeeInstanceID type: %T", t) + } +} + +// SetTeeInstanceID sets the supplied value of Instance ID +func (o *TeeInstanceID) SetTeeInstanceID(val any) 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 TeeInstanceID: %d", t) + } + o.val = val + default: + return fmt.Errorf("unsupported TeeInstanceID type: %T", t) + } + return nil +} + +// valid checks for validity of TeeInstanceID and +// returns an error if Invalid +func (o TeeInstanceID) Valid() error { + if o.val == nil { + return fmt.Errorf("empty TeeInstanceID") + } + switch t := o.val.(type) { + case uint, uint64: + return nil + case []byte: + if len(t) == 0 { + return fmt.Errorf("empty TeeInstanceID") + } + case int: + if t < 0 { + return fmt.Errorf("unsupported negative TeeInstanceID: %d", t) + } + default: + return fmt.Errorf("unsupported TeeInstanceID type: %T", t) + } + return nil +} + +// GetUint returns unsigned integer TeeInstanceID +func (o TeeInstanceID) GetUint() (uint, error) { + switch t := o.val.(type) { + case uint64: + return uint(t), nil + case uint: + return t, nil + default: + return 0, fmt.Errorf("TeeInstanceID type is: %T", t) + } +} + +// GetBytes returns the bytes TeeInstanceID +func (o TeeInstanceID) GetBytes() ([]byte, error) { + switch t := o.val.(type) { + case []byte: + if len(t) == 0 { + return nil, fmt.Errorf("TeeInstanceID type is of zero length") + } + return t, nil + default: + return nil, fmt.Errorf("TeeInstanceID type is: %T", t) + } +} + +// IsBytes returns true if TeeInstanceID is of type []byte array +func (o TeeInstanceID) IsBytes() bool { + return isType[[]byte](o.val) +} + +// IsUnit returns true if TeeInstanceID is of type unsigned integer +func (o TeeInstanceID) IsUint() bool { + return isType[uint64](o.val) || isType[uint](o.val) +} + +// MarshalJSON Marshals TeeInstanceID to JSON +func (o TeeInstanceID) MarshalJSON() ([]byte, error) { + if o.Valid() != nil { + return nil, fmt.Errorf("invalid TeeInstanceID") + } + 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 TeeInstanceID", t) + } + return json.Marshal(v) +} + +// UnmarshalJSON UnMarshals supplied JSON bytes to TeeInstanceID +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 TeeInstanceID 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 TeeInstanceID of type bytes: %w", err) + } + o.val = x + } + return nil +} + +// MarshalCBOR Marshals TeeInstanceID to CBOR +func (o TeeInstanceID) MarshalCBOR() ([]byte, error) { + return cbor.Marshal(o.val) +} + +// UnmarshalCBOR UnMarshals supplied CBOR bytes to TeeInstanceID +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 0000000..8e97608 --- /dev/null +++ b/comid/tdx-profile/teeinstanceid_test.go @@ -0,0 +1,118 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/veraison/corim/comid" +) + +func TestTeeInstanceID_NewTeeInstanceID_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 { + _, err := NewTeeInstanceID(tv.input) + require.Nil(t, err) + } +} + +func TestTeeInstanceID_SetTeeInstanceID_OK(t *testing.T) { + inst := &TeeInstanceID{} + err := inst.SetTeeInstanceID(TestUIntInstance) + require.NoError(t, err) + err = inst.SetTeeInstanceID(TestByteInstance) + require.NoError(t, err) + err = inst.SetTeeInstanceID(uint64(1000)) + require.NoError(t, err) +} + +func TestTeeInstanceID_SetTeeInstanceID_NOK(t *testing.T) { + inst := &TeeInstanceID{} + expectedErr := "unsupported negative TeeInstanceID: -1" + err := inst.SetTeeInstanceID(-1) + assert.EqualError(t, err, expectedErr) + expectedErr = "unsupported TeeInstanceID type: float64" + err = inst.SetTeeInstanceID(-1.234) + assert.EqualError(t, err, expectedErr) +} + +func TestTeeInstanceID_Valid_OK(t *testing.T) { + inst := &TeeInstanceID{TestUIntInstance} + err := inst.Valid() + require.NoError(t, err) +} + +func TestTeeInstanceID_Valid_NOK(t *testing.T) { + tvs := []struct { + desc string + input interface{} + expectedErr string + }{ + { + desc: "unsupported type negative integer", + input: -1, + expectedErr: "unsupported negative TeeInstanceID: -1", + }, + { + desc: "non existent TeeInstanceID", + input: nil, + expectedErr: "empty TeeInstanceID", + }, + { + desc: "non existent TeeInstanceID", + input: []byte{}, + expectedErr: "empty TeeInstanceID", + }, + { + desc: "unsupported type float64", + input: 1.234, + expectedErr: "unsupported TeeInstanceID type: float64", + }, + } + + for _, tv := range tvs { + inst := &TeeInstanceID{tv.input} + err := inst.Valid() + assert.EqualError(t, err, tv.expectedErr) + } +} + +func TestTeeInstanceID_MarshalCBOR_Bytes(t *testing.T) { + inst, err := NewTeeInstanceID(TestByteInstance) + require.Nil(t, err) + 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 TestTeeInstanceID_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 0000000..c8382d8 --- /dev/null +++ b/comid/tdx-profile/teeisvproid.go @@ -0,0 +1,179 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +// 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{} +} + +// NewTeeISVProdID creates a new TeeISVProdID from the +// supplied interface and return a pointer to TeeISVProdID +// Supported values are positive integers and byte array +func NewTeeISVProdID(val interface{}) (*TeeISVProdID, error) { + switch t := val.(type) { + case uint, uint64: + return &TeeISVProdID{val: t}, nil + case []byte: + return &TeeISVProdID{val: t}, nil + case int: + if t < 0 { + return nil, fmt.Errorf("negative integer %d for TeeISVProdID", t) + } + return &TeeISVProdID{val: t}, nil + default: + return nil, fmt.Errorf("unsupported TeeISVProdID type: %T", t) + } +} + +// SetTeeISVProdID sets the supplied value of TeeISVProdID from the interface +// Supported values are either positive integers or byte array +func (o *TeeISVProdID) SetTeeISVProdID(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 TeeISVProdID: %d", t) + } + o.val = val + default: + return fmt.Errorf("unsupported TeeISVProdID type: %T", t) + } + return nil +} + +// Valid checks for validity of TeeISVProdID and returns an error if Invalid +func (o TeeISVProdID) Valid() error { + if o.val == nil { + return fmt.Errorf("empty TeeISVProdID") + } + switch t := o.val.(type) { + case uint, uint64: + return nil + case []byte: + if len(t) == 0 { + return fmt.Errorf("empty TeeISVProdID") + } + case int: + if t < 0 { + return fmt.Errorf("unsupported negative TeeISVProdID: %d", t) + } + default: + return fmt.Errorf("unsupported TeeISVProdID type: %T", t) + } + return nil +} + +// GetUint returns a uint TeeISVProdID +func (o TeeISVProdID) GetUint() (uint, error) { + switch t := o.val.(type) { + case uint64: + return uint(t), nil + case uint: + return t, nil + default: + return 0, fmt.Errorf("TeeISVProdID type is: %T", t) + } +} + +// GetBytes returns a []byte TeeISVProdID +func (o TeeISVProdID) GetBytes() ([]byte, error) { + switch t := o.val.(type) { + case []byte: + if len(t) == 0 { + return nil, fmt.Errorf("TeeISVProdID type is of zero length") + } + return t, nil + default: + return nil, fmt.Errorf("TeeIsvProdID type is: %T", t) + } +} + +// IsBytes returns true if TeeISVProdID is a byte array +func (o TeeISVProdID) IsBytes() bool { + return isType[[]byte](o.val) +} + +// IsUint returns true if TeeISVProdID is a positive integer +func (o TeeISVProdID) IsUint() bool { + return isType[uint64](o.val) || isType[uint](o.val) +} + +// MarshalJSON Marshals TeeISVProdID to JSON +func (o TeeISVProdID) MarshalJSON() ([]byte, error) { + if o.Valid() != nil { + return nil, fmt.Errorf("invalid TeeISVProdID") + } + 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 TeeISVProdID", t) + } + return json.Marshal(v) +} + +// UnmarshalJSON UnMarshals supplied JSON buffer to TeeISVProdID +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 TeeISVProdID 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 TeeISVProdID of type bytes: %w", err) + } + o.val = x + } + return nil +} + +// MarshalCBOR Marshals TeeISVProdID to CBOR bytes +func (o TeeISVProdID) MarshalCBOR() ([]byte, error) { + return cbor.Marshal(o.val) +} + +// UnmarshalCBOR UnMarshals supplied CBOR bytes to TeeISVProdID +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 0000000..110b686 --- /dev/null +++ b/comid/tdx-profile/teeisvproid_test.go @@ -0,0 +1,121 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +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 { + _, err := NewTeeISVProdID(tv.input) + require.Nil(t, err) + } +} + +func TestIsvProdID_SetTeeISVProdID_OK(t *testing.T) { + id := &TeeISVProdID{} + err := id.SetTeeISVProdID(TestUIntISVProdID) + require.NoError(t, err) + err = id.SetTeeISVProdID(TestBytesISVProdID) + require.NoError(t, err) + err = id.SetTeeISVProdID(uint64(1000)) + require.NoError(t, err) +} + +func TestIsvProdID_SetTeeISVProdID_NOK(t *testing.T) { + id := &TeeISVProdID{} + expectedErr := "unsupported negative TeeISVProdID: -1" + err := id.SetTeeISVProdID(-1) + assert.EqualError(t, err, expectedErr) + expectedErr = "unsupported TeeISVProdID type: float64" + err = id.SetTeeISVProdID(-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 TeeISVProdID: -1", + }, + { + desc: "non existent TeeISVProdID", + input: nil, + expectedErr: "empty TeeISVProdID", + }, + { + desc: "non existent TeeISVProdID", + input: []byte{}, + expectedErr: "empty TeeISVProdID", + }, + { + desc: "unsupported type float64", + input: 1.234, + expectedErr: "unsupported TeeISVProdID 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, err := NewTeeISVProdID(TestBytesISVProdID) + require.Nil(t, err) + 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 0000000..bfc20ef --- /dev/null +++ b/comid/tdx-profile/teemiscselect.go @@ -0,0 +1,27 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import "fmt" + +type TeeMiscSelect maskType + +func NewTeeMiscSelect(val []byte) (*TeeMiscSelect, error) { + var miscSelect TeeMiscSelect + if val == nil { + return nil, fmt.Errorf("nil value for TeeMiscSelect") + } + miscSelect = TeeMiscSelect(val) + return &miscSelect, nil +} + +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 0000000..2a796d8 --- /dev/null +++ b/comid/tdx-profile/teemiscselect_test.go @@ -0,0 +1,35 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTeeMiscSelect_NewTeeMiscSelect_OK(t *testing.T) { + _, err := NewTeeMiscSelect(TestTeeMiscSelect) + require.Nil(t, err) +} + +func TestTeeMiscSelect_NewTeeMiscSelect_NOK(t *testing.T) { + expectedErr := "nil value for TeeMiscSelect" + _, err := NewTeeMiscSelect(nil) + assert.EqualError(t, err, expectedErr) +} + +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 0000000..7c9e29b --- /dev/null +++ b/comid/tdx-profile/teepceid.go @@ -0,0 +1,26 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + "fmt" +) + +type TeePCEID string + +func NewTeePCEID(val string) (*TeePCEID, error) { + var pceID TeePCEID + if val == "" { + return nil, fmt.Errorf("null string for TeePCEID") + } + pceID = TeePCEID(val) + return &pceID, nil +} + +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 0000000..927ab42 --- /dev/null +++ b/comid/tdx-profile/teepceid_test.go @@ -0,0 +1,36 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPCEID_NewTeePCEID_OK(t *testing.T) { + _, err := NewTeePCEID(TestPCEID) + require.NoError(t, err) +} + +func TestPCEID_NewTeePCEID_NOK(t *testing.T) { + expectedErr := "null string for TeePCEID" + _, err := NewTeePCEID("") + assert.EqualError(t, err, expectedErr) +} + +func TestPCEID_Valid_OK(t *testing.T) { + pceID, err := NewTeePCEID(TestPCEID) + require.NoError(t, err) + err = pceID.Valid() + require.NoError(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 0000000..ec28fe5 --- /dev/null +++ b/comid/tdx-profile/teetcbcompsvn.go @@ -0,0 +1,36 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package tdx + +import "fmt" + +// MaxSVNCount is the maximum SVN count in TeeTcbCompSvn +const MaxSVNCount = 16 + +type TeeTcbCompSvn [MaxSVNCount]TeeSVN + +func NewTeeTcbCompSVN(val []uint) (*TeeTcbCompSvn, error) { + if len(val) > MaxSVNCount { + return nil, fmt.Errorf("invalid length %d for TeeTcbCompSVN", len(val)) + } else if len(val) == 0 { + return nil, fmt.Errorf("no value supplied for TeeTcbCompSVN") + } + + TeeTcbCompSVN := make([]TeeSVN, MaxSVNCount) + for i, value := range val { + TeeTcbCompSVN[i] = TeeSVN(value) + } + return (*TeeTcbCompSvn)(TeeTcbCompSVN), nil +} + +// 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 0000000..4a65c81 --- /dev/null +++ b/comid/tdx-profile/teetcbstatus.go @@ -0,0 +1,54 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +// nolint:dupl +package tdx + +import "fmt" + +type TeeTcbStatus setType + +func NewTeeTcbStatus(val []any) (*TeeTcbStatus, error) { + var ts TeeTcbStatus + if len(val) == 0 { + return nil, fmt.Errorf("nil value argument") + } + + for i, v := range val { + switch t := v.(type) { + case string: + ts = append(ts, t) + default: + return nil, fmt.Errorf("invalid type: %T for tcb status at index: %d", t, i) + } + } + return &ts, nil +} + +func (o *TeeTcbStatus) AddTeeTcbStatus(val []any) error { + for i, v := range val { + switch t := v.(type) { + case string: + *o = append(*o, t) + default: + return fmt.Errorf("invalid type: %T for tcb status at index: %d", t, i) + } + } + return nil +} + +func (o TeeTcbStatus) Valid() error { + if len(o) == 0 { + return fmt.Errorf("empty tcb status") + } + + for i, v := range o { + switch t := v.(type) { + case string: + continue + default: + return fmt.Errorf("invalid type: %T for tcb status at index: %d", t, i) + } + } + return nil +} diff --git a/comid/tdx-profile/teetcbstatus_test.go b/comid/tdx-profile/teetcbstatus_test.go new file mode 100644 index 0000000..15dc398 --- /dev/null +++ b/comid/tdx-profile/teetcbstatus_test.go @@ -0,0 +1,80 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +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() + _, err := NewTeeTcbStatus(s) + require.NoError(t, err) +} + +func TestTcbStatus_NewTeeTcbStatus_NOK(t *testing.T) { + s := make([]any, len(TestTCBStatus)) + for i := range TestTCBStatus { + s[i] = i + } + expectedErr := "invalid type: int for tcb status at index: 0" + _, err := NewTeeTcbStatus(s) + assert.EqualError(t, err, expectedErr) + var m []any + expectedErr = "nil value argument" + _, err = NewTeeTcbStatus(m) + assert.EqualError(t, err, expectedErr) +} + +func TestTcbStatus_AddTcbStatus_OK(t *testing.T) { + s := initTcbStatus() + status := TeeTcbStatus{} + err := status.AddTeeTcbStatus(s) + require.Nil(t, err) +} + +func TestTcbStatus_AddTcbStatus_NOK(t *testing.T) { + expectedErr := "invalid type: int for tcb status at index: 0" + s := make([]any, len(TestInvalidTCBStatus)) + for i := range TestInvalidTCBStatus { + s[i] = TestInvalidTCBStatus[i] + } + status := TeeTcbStatus{} + err := status.AddTeeTcbStatus(s) + assert.EqualError(t, err, expectedErr) +} + +func TestTcbStatus_Valid_OK(t *testing.T) { + s := initTcbStatus() + status, err := NewTeeTcbStatus(s) + require.Nil(t, err) + 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 at index: 0" + 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 0000000..4e148c6 --- /dev/null +++ b/comid/tdx-profile/test_vars.go @@ -0,0 +1,190 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +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 0000000..f0b8c06 Binary files /dev/null and b/comid/tdx-profile/testcases/comid_pce_refval.cbor differ 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 0000000..10eafdf Binary files /dev/null and b/comid/tdx-profile/testcases/comid_qe_refval.cbor differ 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 0000000..71e9618 Binary files /dev/null and b/comid/tdx-profile/testcases/comid_seam_refval.cbor differ 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 0000000..0ce82c2 --- /dev/null +++ b/comid/tdx-profile/testcases/regen-from-src.sh @@ -0,0 +1,21 @@ +#!/usr/bin/bash +# Copyright 2024-2025 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 0000000..e40b8bd --- /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 0000000..bf06027 --- /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 0000000..32cfe5c --- /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 0000000..faddb11 --- /dev/null +++ b/comid/tdx-profile/types.go @@ -0,0 +1,14 @@ +// Copyright 2025 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +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 5474da0..49de3ba 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 7348dac..a937b7e 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 }