From e42571363322766728bfacac6b329fa7ddd1b238 Mon Sep 17 00:00:00 2001 From: Yogesh Deshpande Date: Mon, 4 Dec 2023 09:49:23 -0500 Subject: [PATCH] Add CCA Realm Verification Plugin Signed-off-by: Yogesh Deshpande --- scheme/cca-realm/evidence_handler.go | 145 ++++++++++++------ scheme/cca-realm/evidence_handler_test.go | 56 +++++++ scheme/cca-realm/test/cca-claims.json | 59 +++++++ .../cca-realm/test/ref-val-endorsement.json | 19 +++ .../cca-realm/test/ref-val-endorsements.json | 3 + vts/cmd/vts-service/en-store.sql | Bin 8192 -> 8192 bytes 6 files changed, 232 insertions(+), 50 deletions(-) create mode 100644 scheme/cca-realm/evidence_handler_test.go create mode 100644 scheme/cca-realm/test/cca-claims.json create mode 100644 scheme/cca-realm/test/ref-val-endorsement.json create mode 100644 scheme/cca-realm/test/ref-val-endorsements.json diff --git a/scheme/cca-realm/evidence_handler.go b/scheme/cca-realm/evidence_handler.go index a9c10b95..b1d874fe 100644 --- a/scheme/cca-realm/evidence_handler.go +++ b/scheme/cca-realm/evidence_handler.go @@ -4,6 +4,8 @@ package cca_realm import ( + "bytes" + "encoding/base64" "encoding/json" "fmt" "net/url" @@ -11,12 +13,10 @@ import ( "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{} @@ -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, @@ -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, @@ -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 } @@ -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 } @@ -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 } diff --git a/scheme/cca-realm/evidence_handler_test.go b/scheme/cca-realm/evidence_handler_test.go new file mode 100644 index 00000000..78a2a4fe --- /dev/null +++ b/scheme/cca-realm/evidence_handler_test.go @@ -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) +} diff --git a/scheme/cca-realm/test/cca-claims.json b/scheme/cca-realm/test/cca-claims.json new file mode 100644 index 00000000..047165e0 --- /dev/null +++ b/scheme/cca-realm/test/cca-claims.json @@ -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" + } + \ No newline at end of file diff --git a/scheme/cca-realm/test/ref-val-endorsement.json b/scheme/cca-realm/test/ref-val-endorsement.json new file mode 100644 index 00000000..5aea9e60 --- /dev/null +++ b/scheme/cca-realm/test/ref-val-endorsement.json @@ -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" + } + } + \ No newline at end of file diff --git a/scheme/cca-realm/test/ref-val-endorsements.json b/scheme/cca-realm/test/ref-val-endorsements.json new file mode 100644 index 00000000..b1f47784 --- /dev/null +++ b/scheme/cca-realm/test/ref-val-endorsements.json @@ -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\"}}" +] \ No newline at end of file diff --git a/vts/cmd/vts-service/en-store.sql b/vts/cmd/vts-service/en-store.sql index 79933165b66eefd562ff9f6d28f59d8c43226408..ef98084591dedcecbac86587cd79a82e5bb64565 100644 GIT binary patch delta 699 zcmZp0XmFSy&B#7c#+i|QW5N=C0XD`@47}61^*D~Q#js3f{Is#~9%E*!92;w+W~Z{V zvtxXatD}#vmA<}#eqesEVPa@yZn>XNK#)mpdTCgZr(;f~Q&wtdmXk}AkEw-0L3)x; zuz7N#TXCglURtqNqDM?YPt!;K=Wo_hd`+Q{F=J9)nB K