Skip to content

Commit

Permalink
feat: implement first phase of TDX Measurement Extensions
Browse files Browse the repository at this point in the history
- Define TDX Extension code points in the Comid Measurement Value Extension Slot
- Provide Examples of TDX Platform(SEAM), Provisioning Certification Enclave(PCE) and TDX Quoting Enclace(QE) Reference Values
- Implement CBOR and JSON Encoding and Decoding of TDX Extension Points to generate TDX CoMIDs
The implementation adheres to
https://datatracker.ietf.org/doc/draft-cds-rats-intel-corim-profile/

Signed-off-by: Yogesh Deshpande <yogesh.deshpande@arm.com>
  • Loading branch information
yogeshbdeshpande committed Jan 28, 2025
1 parent 14a8274 commit 2c3a227
Show file tree
Hide file tree
Showing 34 changed files with 2,566 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ and giving it a new type or a value (for enums).
Please see [extensions documentation](extensions/README.md) for details.



2 changes: 0 additions & 2 deletions comid/digests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions comid/measurement.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down
Empty file added comid/tdx-profile/*.cbor
Empty file.
329 changes: 329 additions & 0 deletions comid/tdx-profile/example_pce_refval_test.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 2c3a227

Please sign in to comment.