Skip to content

Commit

Permalink
Add CCA Realm Verification Plugin
Browse files Browse the repository at this point in the history
Signed-off-by: Yogesh Deshpande <[email protected]>
  • Loading branch information
yogeshbdeshpande committed Dec 4, 2023
1 parent fea2ab2 commit e425713
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 50 deletions.
145 changes: 95 additions & 50 deletions scheme/cca-realm/evidence_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
package cca_realm

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"strings"

"github.com/veraison/ccatoken"
"github.com/veraison/ear"
"github.com/veraison/psatoken"
"github.com/veraison/services/handler"
"github.com/veraison/services/log"
"github.com/veraison/services/proto"
"github.com/veraison/services/scheme/common"
"github.com/veraison/services/scheme/common/arm"
)

type EvidenceHandler struct{}
Expand Down Expand Up @@ -53,14 +53,21 @@ func (s EvidenceHandler) SynthKeysFromRefValue(

return nil, fmt.Errorf("unable to UnMarshal Realm Attributes %w", err)
}
lookupKey := RefValLookupKey(SchemeName, tenantID, realm.RealmID)
if realm.MeasurementArray == nil {
return nil, fmt.Errorf("no measurements in Realm Endorsements %w", err)
}

rim := base64.StdEncoding.EncodeToString(realm.MeasurementArray[0])
log.Debugf("base64 encoded rim value = %s", rim)

lookupKey := RefValLookupKey(SchemeName, tenantID, rim)
log.Debugf("Scheme %s Plugin Reference Value Look Up Key= %s\n", SchemeName, lookupKey)

return []string{lookupKey}, nil
}

func RefValLookupKey(schemeName, tenantID, uuID string) string {
absPath := []string{uuID}
func RefValLookupKey(schemeName, tenantID, rim string) string {
absPath := []string{rim}

u := url.URL{
Scheme: schemeName,
Expand All @@ -81,7 +88,7 @@ func (s EvidenceHandler) GetTrustAnchorID(token *proto.AttestationToken) (string
return "", nil
}

// TO DO COMPLETE THIS
// ExtractClaims extract Realm Claims and set the extracted Reference ID
func (s EvidenceHandler) ExtractClaims(
token *proto.AttestationToken,
trustAnchor string,
Expand All @@ -107,20 +114,22 @@ func (s EvidenceHandler) ExtractClaims(
"could not convert realm claims: %w", err))
}

/* FROM THE REALM CLAIM SET GET THE REALM INITIAL MEASUREMENTS */
/* THAT WILL BE THE INPUT TO THE REFERENCE ID */

extracted.ClaimsSet = map[string]interface{}{
"platform": platformClaimsSet,
"realm": realmClaimsSet,
}

extracted.ReferenceID = arm.RefValLookupKey(
brim, err := ccaToken.RealmClaims.GetInitialMeasurement()
if err != nil {
return nil, handler.BadEvidence(err)
}
rim := base64.StdEncoding.EncodeToString(brim)
log.Debugf("base64 encoded rim value = %s", rim)

extracted.ReferenceID = RefValLookupKey(
SchemeName,
token.TenantId,
arm.MustImplIDString(ccaToken.PlatformClaims),
)

rim)
log.Debugf("extracted Reference ID Key = %s", extracted.ReferenceID)
return &extracted, nil
}
Expand Down Expand Up @@ -159,8 +168,6 @@ func (s EvidenceHandler) AppraiseEvidence(

err := populateAttestationResult(result, ec.Evidence.AsMap(), endorsements)

// TO DO: Handle Unprocessed evidence when new Attestation Result interface
// is ready. Please see issue #105
return result, err
}

Expand All @@ -169,57 +176,95 @@ func populateAttestationResult(
evidence map[string]interface{},
endorsements []handler.Endorsement,
) error {
claims, err := common.MapToClaims(evidence["platform"].(map[string]interface{}))
claims, err := mapToClaims(evidence["realm"].(map[string]interface{}))
if err != nil {
return err
}

appraisal := result.Submods[SchemeName]

// once the signature on the token is verified, we can claim the HW is
// authentic
appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim

rawLifeCycle, err := claims.GetSecurityLifeCycle()
// Match RIM Values first
brim, err := claims.GetInitialMeasurement()
if err != nil {
return handler.BadEvidence(err)
return fmt.Errorf("failed to get Realm Initial Measurements from Claims")
}
rim := base64.StdEncoding.EncodeToString(brim)
log.Debugf("base64 encoded rim value = %s", rim)

for _, endorsement := range endorsements {
var realmEnd RealmAttr
json.Unmarshal(endorsement.Attributes, &realmEnd)
er := realmEnd.MeasurementArray[0]
erim := base64.StdEncoding.EncodeToString(er)
log.Debugf("base64 encoded endorsement rim value = %s", erim)

if rim == erim {
appraisal.TrustVector.Executables = ear.ApprovedBootClaim
log.Debug("realm Initial Measurement match Success")

} else {
appraisal.TrustVector.Executables = ear.ContraindicatedRuntimeClaim
log.Debug("realm Initial Measurement match Failed")
}

lifeCycle := psatoken.CcaLifeCycleToState(rawLifeCycle)
if lifeCycle == psatoken.CcaStateSecured ||
lifeCycle == psatoken.CcaStateNonCcaPlatformDebug {
appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim
appraisal.TrustVector.RuntimeOpaque = ear.ApprovedRuntimeClaim
appraisal.TrustVector.StorageOpaque = ear.HwKeysEncryptedSecretsClaim
} else {
appraisal.TrustVector.InstanceIdentity = ear.UntrustworthyInstanceClaim
appraisal.TrustVector.RuntimeOpaque = ear.VisibleMemoryRuntimeClaim
appraisal.TrustVector.StorageOpaque = ear.UnencryptedSecretsClaim
if appraisal.TrustVector.Executables == ear.ApprovedBootClaim {
execmatch, err := matchExecutables(claims, realmEnd)
if err != nil {
appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim
break
}
// Match REM Values to express Execution
if execmatch {
appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim
log.Debug("Boot claim and run time both succeedded")

} else {
appraisal.TrustVector.Executables = ear.UnsafeRuntimeClaim
log.Debug("Boot claim succeedded but run time both Failed")
}
break
}
}
appraisal.UpdateStatusFromTrustVector()

swComps := arm.FilterRefVal(endorsements, "CCA_SSD_PLATFORM.sw-component")
match := arm.MatchSoftware(SchemeName, claims, swComps)
if match {
appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim
log.Debug("matchSoftware Success")
return nil
}

} else {
appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim
log.Debug("matchSoftware Failed")
func mapToClaims(in map[string]interface{}) (*ccatoken.RealmClaims, error) {
var cca ccatoken.RealmClaims
data, err := json.Marshal(in)
if err != nil {
return nil, err
}
err = cca.FromJSON(data)
if err != nil {
return nil, fmt.Errorf("unable to map claims for RealmClaims %w", err)
}
return &cca, nil
}

platformConfig := arm.FilterRefVal(endorsements, "CCA_SSD_PLATFORM.platform-config")
match = arm.MatchPlatformConfig(SchemeName, claims, platformConfig)
func matchExecutables(rc *ccatoken.RealmClaims, re RealmAttr) (bool, error) {

if match {
appraisal.TrustVector.Configuration = ear.ApprovedConfigClaim
log.Debug("matchPlatformConfig Success")
if rc == nil {
return false, fmt.Errorf("no realm claims in matchExecutables")
}
rems, err := rc.GetExtensibleMeasurements()
if err != nil {
return false, fmt.Errorf("unable to matchExecutables %w", err)
}

} else {
appraisal.TrustVector.Configuration = ear.UnsafeConfigClaim
log.Debug("matchPlatformConfig Failed")
matched := false
for _, meas := range rems {
matched = false
for _, emeas := range re.MeasurementArray {
if bytes.Equal(meas, emeas) {
matched = true
}
}
if !matched {
return !matched, nil
}
}
appraisal.UpdateStatusFromTrustVector()

return nil
return matched, nil
}
56 changes: 56 additions & 0 deletions scheme/cca-realm/evidence_handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2021-2023 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cca_realm

import (
"encoding/json"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/veraison/ear"
"github.com/veraison/services/handler"
"github.com/veraison/services/proto"
)

func Test_SynthKeysFromRefValue_ok(t *testing.T) {
endorsementsBytes, err := os.ReadFile("test/ref-val-endorsement.json")
require.NoError(t, err)

var endors handler.Endorsement
err = json.Unmarshal(endorsementsBytes, &endors)
require.NoError(t, err)
expectedKey := "CCA_REALM://1/QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1"

scheme := &EvidenceHandler{}
key_list, err := scheme.SynthKeysFromRefValue("1", &endors)
require.NoError(t, err)
assert.Equal(t, expectedKey, key_list[0])
}

func Test_AppraiseEvidence_ok(t *testing.T) { // nolint: dupl
extractedBytes, err := os.ReadFile("test/cca-claims.json")
require.NoError(t, err)

var ec proto.EvidenceContext
err = json.Unmarshal(extractedBytes, &ec)
require.NoError(t, err)

var endorsemementsArray []string
endorsementsBytes, err := os.ReadFile("test/ref-val-endorsements.json")
require.NoError(t, err)
err = json.Unmarshal(endorsementsBytes, &endorsemementsArray)
require.NoError(t, err)

scheme := &EvidenceHandler{}

result, err := scheme.AppraiseEvidence(&ec, endorsemementsArray)
require.NoError(t, err)

attestation := result.Submods["CCA_REALM"]

assert.Equal(t, ear.TrustTierAffirming, *attestation.Status)
assert.Equal(t, attestation.TrustVector.Executables, ear.ApprovedRuntimeClaim)
}
59 changes: 59 additions & 0 deletions scheme/cca-realm/test/cca-claims.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"evidence": {
"platform": {
"cca-platform-profile": "http://arm.com/CCA-SSD/1.0.0",
"cca-platform-challenge": "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA=",
"cca-platform-implementation-id": "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA=",
"cca-platform-instance-id": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC",
"cca-platform-config":"AQID",
"cca-platform-lifecycle": 12288,
"cca-platform-sw-components": [
{
"measurement-description": "TF-M_SHA256MemPreXIP",
"measurement-type": "BL",
"measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"version": "3.4.2"
},
{
"measurement-type": "M1",
"measurement-value": "CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"version": "1.2.0"
},
{
"measurement-type": "M2",
"measurement-value": "DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"version": "1.2.3"
},
{
"measurement-type": "M3",
"measurement-value": "EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=",
"version": "1.0.0"
}
],
"cca-platform-service-indicator" : "https://veraison.example/v1/challenge-response",
"cca-platform-hash-algo-id": "sha-256"
},
"realm": {
"cca-realm-challenge": "byTWuWNaLIu/WOkIuU4Ewb+zroDN6+gyQkV4SZ/jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA==",
"cca-realm-personalization-value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==",
"cca-realm-initial-measurement": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1",
"cca-realm-extensible-measurements": [
"IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4",
"QQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4",
"JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4",
"MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4"
],
"cca-realm-hash-algo-id": "sha-256",
"cca-realm-public-key": "BIL70TKptcOWh5+7FTQNkFCXjlXHnVJ5oroOlYVPN+IM0vZPO3K1cLvXc+7iznaEJe31Re2+if+v4OlrvUbicPIHlsRIuY2vRqdk0nRC5ubthPjOyBfm7ManHTo959Z+zQ==",
"cca-realm-public-key-hash-algo-id": "sha-512"
}
},
"reference-id": "CCA_SSD_PLATFORM://1/BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=/AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY",
"trust-anchor-id": "CCA_SSD_PLATFORM://1/BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=/",
"tenant-id": "1"
}

19 changes: 19 additions & 0 deletions scheme/cca-realm/test/ref-val-endorsement.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"scheme": "CCA_REALM",
"type": "reference value",
"subType": "",
"attributes": {
"cca-realm.alg-id": "sha-384",
"cca-realm.id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c",
"cca-realm.measurement-array": [
"QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1",
"IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4",
"QQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4",
"JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4",
"MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4"
],
"cca-realm.model": "",
"cca-realm.vendor": "Workload Client Ltd"
}
}

3 changes: 3 additions & 0 deletions scheme/cca-realm/test/ref-val-endorsements.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
"{ \"scheme\": \"CCA_REALM\", \"type\": \"reference value\",\"subType\": \"\", \"attributes\": { \"cca-realm.alg-id\": \"sha-384\",\"cca-realm.id\": \"cd1f0e55-26f9-460d-b9d8-f7fde171787c\", \"cca-realm.measurement-array\": [\"QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1\",\"IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4\",\"QQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4\",\"JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4\",\"MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4\"],\"cca-realm.model\": \"\", \"cca-realm.vendor\": \"Workload Client Ltd\"}}"
]
Binary file modified vts/cmd/vts-service/en-store.sql
Binary file not shown.

0 comments on commit e425713

Please sign in to comment.