From cbf634ed6ea43fd6c6d4b75491f862bf4fee8242 Mon Sep 17 00:00:00 2001 From: setrofim Date: Wed, 14 Jan 2026 14:21:25 +0000 Subject: [PATCH 1/3] fix(make): move TOPDIR into mk/common.mk Move the definition of TOPDIR from the top-level Makefile into mk/common.mk. This ensures that the definition is available when invoking a sub-Makefile directly (e.g. make -C vts/cmd/vts-service). This, in turn, makes sure the pat to get-veraison-version script gets resolved correctly, and the version gets embedded into the executable. Signed-off-by: Sergei Trofimov --- Makefile | 4 +--- mk/common.mk | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9a544119..78b3398b 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,6 @@ -# Copyright 2021-2025 Contributors to the Veraison project. +# Copyright 2021-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -export TOPDIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) - # There will be one plugin built for each scheme. Removing this definition will # cause a separate plugin to be built for each handler interface (endorsement, # store, and verification), resulting in three plugins per scheme. diff --git a/mk/common.mk b/mk/common.mk index c98e73b3..9a2d316a 100644 --- a/mk/common.mk +++ b/mk/common.mk @@ -1,10 +1,11 @@ -# Copyright 2021 Contributors to the Veraison project. +# Copyright 2021-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 SHELL := /bin/bash # Pass this to sub-make export GO111MODULE := on +export TOPDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/..) # Used to set the ServerVersion reported by services VERSION_FROM_GIT := $(shell $(TOPDIR)/scripts/get-veraison-version) From a0e9f2743bd23b31fc0768602bffa3d2f5fcaae7 Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Tue, 27 Jan 2026 14:41:56 +0000 Subject: [PATCH 2/3] chore: add coserv-service to .gitignore Avoid accidentally committing built artifact. Signed-off-by: Sergei Trofimov --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c405ae26..41cac9e5 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ __generated__ __pycache__ __debug_bin* management/cmd/management-service/management-service +coserv/cmd/coserv-service/coserv-service # Test binary, built with `go test -c` *.test From e8b6af7c5a03e35ebc027cb7adbde22f7883198a Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Tue, 27 Jan 2026 14:43:27 +0000 Subject: [PATCH 3/3] feat!: switch to CoRIM store for endorsements and trust anchors Switch to using CoRIM store, rather than the key-value store, for endorsements and trust anchors. Endorsement and trust anchors are now stored in a format that preserves the entire CoRIM/CoMID contents, and is entirely scheme-agnostic. The more sophisticated structures allows for more sophisticated a management life cycle to be implemented in the future, and the more generic structure makes scheme implementation easier. This change has a huge knock-on effect on both provisioning and verification pipelines implementations, and the scheme implementation framework has been completely restructured: - IEvidenceHander, IEndrosementHander, and IStoreHander interfaces are gone, replaced by the single ISchemeHander interface. - A generic scheme wrapper implements ISchemeHander based on a smaller ISchemeImplementation interface and a SchemeDescriptor. Most schemes just need to implment ISchemeImplementation and provide the SchemeDescriptor. - The SchemeDescriptor is a declarative element, grouping static information about the scheme, such as its name, supported media types, etc (in the past, this was defined on ad-hoc basis using multiple variables within old scheme implementations). - Scheme version has also been added as part of the descriptor. This isn't really used at the moment. All existing schemes have been set to version 1.0. (note: this isn't used at the moment) - ISchemeHander/ISchemeImplementation expose similar API to the old IEvidenceHander (verification pipeline stages remain the same), but the argument types differ; e.g. "keys" for endorsement/trust anchor lookup are now represented as comid.Environment's. - Instead of IEndrosementHander methods, ISchemeHander has a single ValidateCorim (made option in the ISchemeImplementation by the wrapper). This allows schemes to supply custom validation for CoRIMs before they are added to the store (this can also be more cleanly done via CoRIM profiles). - IStoreHander mothods are no longer necessary as the store interface is entirely scheme-agnostic. - Protobuf types have been removed from the IStoreHander methods. Protobuf is an implementation of the underlying RPC mechanisms and should not be exposed to the schemes (effectively burdening them with partial serialisation for transport). CoRIM store is initialized and managed by its own client. Deployments have been updated to integrate it. Since there is now a single scheme interface, the combined/split plugins configuration has been removed. There is now always one plugin per scheme. Plugin executables have also been renamed to be prefixed with scheme- or coserv- depending on plugin types (as CoSERV plugins currently reside under scheme/). Since there is now a single interface for the entire scheme, IPluggable.GetSupportedMediaTypes() has been changed to return a map[string][]string instead of just []string. This allows to separate provisioning from verification media types. An "example" scheme has been added containing the boilerplate template for imlementing new schemes. BREAKING CHANGE: the scheme implementation framework is completely different; old scheme implementations will not work with this update, and will need to be re-written to implement the new ISchemeImplementation interface. Legacy CoRIM media type application/corim-usnigned+cbor has been removed. IPluggable.GetSupportedMediaTypes() now returns a map[string][]string instead of []string. Signed-off-by: Sergei Trofimov --- .gitignore | 1 + .golangci.yml | 21 +- Makefile | 11 +- auth/keycloak.go | 20 +- builtin/builtin_loader.go | 33 +- builtin/builtin_manager.go | 21 +- builtin/schemes.go | 34 +- coserv/test-harness/amd.sh | 2 + coserv/test-harness/nvidia.sh | 2 + coserv/test-harness/query.sh | 2 + deployments/aws/bin/veraison | 26 +- deployments/aws/deployment.sh | 2 + deployments/aws/misc/sentinel-commands | 108 ++- .../aws/templates/image-sentinel.pkr.hcl | 14 +- deployments/debian/debian/postinst | 2 + deployments/debian/debian/prerm | 2 + deployments/debian/deployment.sh | 3 +- deployments/docker/src/builder-dispatcher | 11 +- deployments/docker/src/builder.docker | 3 +- deployments/docker/src/config.yaml.template | 15 +- .../src/corim-store-config.yaml.template | 2 + deployments/docker/src/manager-dispatcher | 25 +- deployments/docker/src/manager.docker | 3 +- deployments/docker/veraison | 35 +- deployments/native/README.md | 7 + deployments/native/bin/veraison | 39 +- deployments/native/bootstrap/arch.sh | 3 +- deployments/native/bootstrap/macosx-brew.sh | 3 +- deployments/native/bootstrap/oraclelinux.sh | 4 +- deployments/native/bootstrap/ubuntu.sh | 4 +- .../native/config/corim-store.yaml.template | 2 + .../native/config/services.yaml.template | 45 +- deployments/native/deployment.sh | 20 +- deployments/native/env/env.bash | 1 + deployments/native/env/env.zsh | 1 + deployments/rpm/deployment.sh | 2 + end-to-end/end-to-end-docker | 6 +- end-to-end/end-to-end-native | 6 +- .../cca-claims-without-realm-challenge.json | 3 +- end-to-end/input/cca-endorsements.cbor | Bin 1108 -> 1108 bytes end-to-end/input/cca-evidence.cbor | Bin 1393 -> 1425 bytes end-to-end/input/cca-realm-endorsements.cbor | Bin 765 -> 722 bytes end-to-end/input/psa-endorsements.cbor | Bin 836 -> 857 bytes end-to-end/input/psa-evidence.cbor | Bin 546 -> 546 bytes end-to-end/input/src/cca-evidence.json | 3 +- .../input/src/comid-cca-realm-refval.json | 9 +- end-to-end/input/src/corim-cca-realm.json | 32 +- end-to-end/input/src/corim-cca.json | 2 +- end-to-end/input/src/corim-psa.json | 2 +- go.mod | 98 +-- go.sum | 192 ++++-- handler/coservproxy_rpc.go | 25 +- handler/endorsement.go | 24 - handler/endorsement_rpc.go | 205 ------ handler/evidence_rpc.go | 276 -------- handler/idecoder_manager.go | 13 - handler/iendorsementhandler.go | 32 - handler/ievidencehandler.go | 52 -- handler/ischemehandler.go | 59 ++ handler/ischemeimplementation.go | 38 ++ handler/istorehandler.go | 43 -- handler/plugin.go | 21 +- handler/scheme_rpc.go | 427 ++++++++++++ handler/schemedescriptor.go | 70 ++ handler/schemeimplementationwrapper.go | 183 ++++++ handler/store_rpc.go | 304 --------- integration-tests/Makefile | 2 +- .../endorsements/corim-enacttrust-badta.cbor | Bin 166 -> 166 bytes .../endorsements/corim-enacttrust-mini.json | 2 +- integration-tests/docker/Dockerfile | 3 +- integration-tests/tests/common.yaml | 6 +- .../tests/test_enacttrust_badkey.tavern.yaml | 2 +- .../tests/test_end_to_end.tavern.yaml | 12 +- .../test_provisioning_empty_body.tavern.yaml | 2 +- ...test_provisioning_unauthorized.tavern.yaml | 2 +- ...ification_bad_session_attester.tavern.yaml | 2 +- integration-tests/utils/checkers.py | 5 +- integration-tests/utils/generators.py | 22 +- integration-tests/utils/hooks.py | 10 +- integration-tests/utils/util.py | 10 +- kvstore/sql.go | 40 +- kvstore/sql_test.go | 36 +- log/log.go | 14 +- management/api/router.go | 4 +- management/cmd/management-service/main.go | 8 +- management/policy.go | 10 +- mk/test.mk | 2 +- plugin/goplugin_context.go | 4 +- plugin/goplugin_loader.go | 26 +- plugin/goplugin_manager.go | 25 +- plugin/imanager.go | 6 +- plugin/ipluggable.go | 9 +- plugin/test/ammo.go | 43 +- plugin/test/gascartridge/gascartridge.go | 6 +- plugin/test/mook.go | 43 +- plugin/test/powercell/powercell.go | 6 +- plugin/test/redshirt/redshirt.go | 6 +- plugin/test/trooper/trooper.go | 6 +- policy/agent.go | 44 +- policy/agent_test.go | 43 +- policy/iagent.go | 12 +- policy/ibackend.go | 12 +- policy/mocks/mock_ibackend.go | 4 +- policy/opa.go | 48 +- policy/opa_test.go | 30 +- policy/test/evaluate-vectors.json | 12 +- ...orsements.json => empty-endorsements.json} | 0 .../test/inputs/parsec-cca-endorsements.json | 79 ++- policy/test/inputs/psa-endorsements.json | 48 +- proto/Makefile | 1 + proto/appraisal_context.pb.go | 4 +- proto/endorsement_query.pb.go | 11 +- proto/evidence.pb.go | 4 +- proto/scheme.pb.go | 396 +++++++++++ proto/scheme.pb.json.go | 72 ++ proto/scheme.proto | 28 + proto/state.pb.go | 4 +- proto/status.pb.go | 4 +- proto/token.pb.go | 4 +- proto/vts.pb.go | 4 +- proto/vts_grpc.pb.go | 4 - provisioning/api/router.go | 5 +- provisioning/cmd/provisioning-service/main.go | 4 +- provisioning/test-harness/req.sh | 2 +- scheme/MIGRATING.md | 95 --- scheme/Makefile | 16 +- scheme/README.md | 226 ++++++- scheme/amd-kds-coserv/coserv_handler.go | 6 +- scheme/amd-kds-coserv/plugin/Makefile | 15 +- .../amd-kds-coserv/plugin/combined/Makefile | 11 - scheme/amd-kds-coserv/plugin/combined/main.go | 15 - .../plugin/coserv-handler/Makefile | 11 - .../plugin/{coserv-handler => }/main.go | 2 +- scheme/arm-cca/Makefile | 2 +- scheme/arm-cca/README.md | 84 --- scheme/arm-cca/corim.go | 169 +++++ scheme/arm-cca/corim_extractor.go | 43 -- scheme/arm-cca/corim_test.go | 89 +++ scheme/arm-cca/endorsement_handler.go | 142 ---- scheme/arm-cca/endorsement_handler_test.go | 150 ----- scheme/arm-cca/evidence_handler.go | 154 ----- scheme/arm-cca/evidence_handler_test.go | 217 ------- scheme/arm-cca/platform.go | 74 --- scheme/arm-cca/plugin/Makefile | 16 +- scheme/arm-cca/plugin/combined/Makefile | 11 - scheme/arm-cca/plugin/combined/main.go | 16 - .../plugin/endorsement-handler/Makefile | 11 - .../plugin/endorsement-handler/main.go | 14 - .../arm-cca/plugin/evidence-handler/Makefile | 11 - .../plugin/{evidence-handler => }/main.go | 4 +- scheme/arm-cca/plugin/store-handler/Makefile | 11 - scheme/arm-cca/plugin/store-handler/main.go | 14 - scheme/arm-cca/realm.go | 148 ----- scheme/arm-cca/scheme.go | 563 +++++++++++++++- scheme/arm-cca/store_handler.go | 156 ----- scheme/arm-cca/store_handler_test.go | 94 --- .../arm-cca/test/corim/build-test-vectors.sh | 68 -- .../test/corim/compile-endorsements.sh | 16 + .../corim-cca-platform-bad-no-class.cbor | Bin 0 -> 351 bytes ...orim-cca-platform-bad-refval-instance.cbor | Bin 0 -> 604 bytes .../corim-cca-platform-bad-refval-mkey.cbor | Bin 0 -> 213 bytes ...im-cca-platform-bad-refval-no-digests.cbor | Bin 0 -> 232 bytes ...corim-cca-platform-bad-refval-no-mkey.cbor | Bin 0 -> 211 bytes ...-cca-platform-bad-refval-no-raw-value.cbor | Bin 0 -> 226 bytes .../corim/corim-cca-platform-bad-ta-cert.cbor | Bin 0 -> 2493 bytes .../corim-cca-platform-bad-ta-instance.cbor | Bin 0 -> 392 bytes ...corim-cca-platform-bad-ta-no-instance.cbor | Bin 0 -> 352 bytes .../test/corim/corim-cca-platform-valid.cbor | Bin 0 -> 860 bytes .../corim/corim-cca-realm-bad-instance.cbor | Bin 0 -> 616 bytes .../corim-cca-realm-bad-no-instance.cbor | Bin 0 -> 617 bytes .../corim-cca-realm-bad-no-integ-regs.cbor | Bin 0 -> 275 bytes .../corim-cca-realm-bad-no-raw-value.cbor | Bin 0 -> 577 bytes .../test/corim/corim-cca-realm-valid.cbor | Bin 0 -> 647 bytes .../src/comid-cca-platform-bad-no-class.json | 24 + ...omid-cca-platform-bad-refval-instance.json | 98 +++ .../comid-cca-platform-bad-refval-mkey.json | 33 + ...id-cca-platform-bad-refval-no-digests.json | 38 ++ ...comid-cca-platform-bad-refval-no-mkey.json | 29 + ...cca-platform-bad-refval-no-raw-value.json} | 27 +- .../src/comid-cca-platform-bad-ta-cert.json | 30 + .../comid-cca-platform-bad-ta-instance.json | 30 + ...comid-cca-platform-bad-ta-no-instance.json | 26 + .../corim/src/comid-cca-platform-refval.json | 94 +++ .../test/corim/src/comid-cca-platform-ta.json | 30 + ...json => comid-cca-realm-bad-instance.json} | 37 +- .../src/comid-cca-realm-bad-no-instance.json | 62 ++ .../comid-cca-realm-bad-no-integ-regs.json | 28 + ... => comid-cca-realm-bad-no-raw-value.json} | 26 +- ...Class.json => comid-cca-realm-refval.json} | 35 +- .../arm-cca/test/corim/src/comidCcaRealm.json | 79 --- .../src/comidCcaRealmInvalidInstance.json | 75 --- .../test/corim/src/comidCcaRefValOne.json | 49 -- .../test/corim/src/corim-cca-platform.json | 12 + .../test/corim/src/corim-cca-realm.json | 12 + scheme/arm-cca/test/corim/src/corimCca.json | 23 - .../test/corim/src/corimCcaNoProfile.json | 22 - .../arm-cca/test/corim/src/corimCcaRealm.json | 17 - .../test/corim/src/platform-corims.yaml | 25 + .../arm-cca/test/corim/src/realm-corims.yaml | 14 + .../test/corim/submit-arm-cca-endorsements.sh | 7 + .../unsignedCorimCcaComidCcaRefValFour.cbor | Bin 671 -> 0 bytes .../unsignedCorimCcaComidCcaRefValOne.cbor | Bin 390 -> 0 bytes ...edCorimCcaNoProfileComidCcaRefValFour.cbor | Bin 644 -> 0 bytes ...nedCorimCcaNoProfileComidCcaRefValOne.cbor | Bin 363 -> 0 bytes .../unsignedCorimCcaRealmComidCcaRealm.cbor | Bin 669 -> 0 bytes ...orimCcaRealmComidCcaRealmInvalidClass.cbor | Bin 672 -> 0 bytes ...mCcaRealmComidCcaRealmInvalidInstance.cbor | Bin 584 -> 0 bytes ...gnedCorimCcaRealmComidCcaRealmNoClass.cbor | Bin 556 -> 0 bytes ...dCorimCcaRealmComidCcaRealmNoInstance.cbor | Bin 545 -> 0 bytes scheme/arm-cca/test/evidence/cca-good.cbor | Bin 0 -> 1393 bytes scheme/arm-cca/test/evidence/cca-token.cbor | Bin 1404 -> 0 bytes scheme/arm-cca/test/evidence/cca-token.json | 52 -- .../test/evidence/compile-cca-evidence.sh | 10 + .../test/evidence/extracted-claims.json | 53 -- scheme/arm-cca/test/evidence/extracted.json | 58 -- .../arm-cca/test/evidence/src/cca-good.json | 52 ++ scheme/arm-cca/test/evidence/src/ec.p256.jwk | 9 + scheme/arm-cca/test/evidence/src/ec.p384.jwk | 8 + .../test/evidence/submit-arm-cca-evidence.sh | 18 + .../arm-cca/test/platform/endorsements.json | 7 - .../platform/invalid-key-ta-endorsements.json | 11 - .../platform/mismatch-cfg-endorsements.json | 7 - .../mismatch-refval-endorsements.json | 7 - .../test/platform/mult-endorsements.json | 5 - .../test/platform/refval-endorsements.json | 12 - .../test/platform/ta-endorsements.json | 11 - .../test/platform/ta-integ-endorsements.json | 11 - .../test/realm/match-endorsements.json | 8 - .../test/realm/no-realm-endorsements.json | 7 - .../test/realm/no-rem-endorsements.json | 8 - .../test/realm/no-rpv-endorsements.json | 8 - .../test/realm/rim-mismatch-endorsements.json | 8 - scheme/arm-cca/test_vars.go | 54 ++ scheme/arm-cca/test_vectors.go | 36 - scheme/common/Makefile | 6 +- scheme/common/arm/Makefile | 13 - scheme/common/arm/coservrepackager.go | 129 ---- scheme/common/arm/handlers.go | 224 ------- scheme/common/arm/lookup.go | 64 -- scheme/common/arm/platform/classattributes.go | 47 -- scheme/common/arm/platform/imeasurement.go | 19 - .../common/arm/platform/instanceattributes.go | 26 - .../common/arm/platform/swcompattributes.go | 96 --- .../arm/platform/swcompattributes_test.go | 50 -- scheme/common/cca/Makefile | 14 - .../common/cca/platform/cca_ssd_extractor.go | 168 ----- .../cca/platform/ccaplatformconfigid.go | 63 -- scheme/common/cca/realm/realm_attributes.go | 109 ---- .../common/cca/realm/realm_classattributes.go | 46 -- scheme/common/cca/realm/realm_extractor.go | 108 --- scheme/common/cca/realm/realm_handlers.go | 40 -- .../cca/realm/realm_instanceattributes.go | 29 - scheme/common/cca/realm/realm_utils.go | 99 --- scheme/common/corim.go | 160 +++++ scheme/common/iextractor.go | 24 - scheme/common/scripts/gen-corim | 21 - scheme/common/signedcorim_decoder.go | 99 --- scheme/common/unsignedcorim_decoder.go | 94 --- scheme/common/util.go | 50 ++ scheme/common/utils.go | 125 ---- scheme/example/Makefile | 14 + scheme/example/README.md | 28 + scheme/example/corim.go | 30 + scheme/example/plugin/Makefile | 11 + scheme/example/plugin/main.go | 14 + scheme/example/scheme.go | 76 +++ scheme/nvidia-coserv/coserv_handler.go | 6 +- scheme/nvidia-coserv/plugin/Makefile | 12 +- scheme/nvidia-coserv/plugin/combined/Makefile | 11 - .../plugin/coserv-handler/Makefile | 11 - .../plugin/coserv-handler/main.go | 15 - .../plugin/{combined => }/main.go | 2 +- scheme/parsec-cca/Makefile | 3 +- scheme/parsec-cca/corim.go | 37 ++ scheme/parsec-cca/corim_test.go | 20 + scheme/parsec-cca/corim_test_vectors.go | 14 - scheme/parsec-cca/endorsement_handler.go | 56 -- scheme/parsec-cca/endorsement_handler_test.go | 86 --- scheme/parsec-cca/evidence_handler.go | 214 ------ scheme/parsec-cca/evidence_handler_test.go | 210 ------ scheme/parsec-cca/parsec_cca_extractor.go | 37 -- scheme/parsec-cca/plugin/Makefile | 16 +- scheme/parsec-cca/plugin/combined/Makefile | 11 - scheme/parsec-cca/plugin/combined/main.go | 16 - .../plugin/endorsement-handler/Makefile | 11 - .../plugin/evidence-handler/Makefile | 11 - .../plugin/evidence-handler/main.go | 14 - .../plugin/{endorsement-handler => }/main.go | 4 +- .../parsec-cca/plugin/store-handler/Makefile | 11 - .../parsec-cca/plugin/store-handler/main.go | 14 - scheme/parsec-cca/scheme.go | 201 +++++- scheme/parsec-cca/store_handler.go | 72 -- scheme/parsec-cca/store_handler_test.go | 82 --- .../test/corim/build-test-vectors.sh | 23 - .../test/corim/compile-endorsements.sh | 15 + .../test/corim/corim-parsec-cca-valid.cbor | Bin 0 -> 960 bytes .../corim/src/ComidParsecCcaMultRefVal.json | 108 --- .../corim/src/comid-parsec-cca-refval.json | 106 +++ .../test/corim/src/comid-parsec-cca-ta.json} | 18 +- .../test/corim/src/corim-parsec-cca.json | 4 + .../test/corim/src/corimParsecCca.json | 23 - scheme/parsec-cca/test/corim/src/corims.yaml | 7 + .../corim/submit-parsec-cca-endorsements.sh | 6 + ...orimParsecCcaComidParsecCcaMultRefVal.cbor | Bin 790 -> 0 bytes ...CorimParsecCcaComidParsecCcaRefValOne.cbor | Bin 411 -> 0 bytes .../test/evidence/bad_evidence.cbor | Bin 655 -> 0 bytes .../test/evidence/bad_key_endorsements.json | 11 - .../evidence/bad_key_header_endorsements.json | 11 - .../test/evidence/bad_key_private_key.json | 11 - .../evidence/compile-parsec-cca-evidence.sh | 27 + scheme/parsec-cca/test/evidence/evidence.cbor | Bin 1336 -> 1494 bytes .../parsec-cca/test/evidence/extracted.json | 52 -- .../mismatch_cfg_refval_endorsements.json | 7 - .../mismatch_swcomp_refval_endorsements.json | 7 - .../test/evidence/refval_endorsement.json | 12 - .../test/evidence/refval_endorsements.json | 7 - .../evidence/src/cca-claims.json.template | 52 ++ .../parsec-cca/test/evidence/src/ec.p256.jwk | 9 + .../parsec-cca/test/evidence/src/ec.p384.jwk | 8 + scheme/parsec-cca/test/evidence/src/kat.diag | 11 + .../evidence/submit-parsec-cca-evidence.sh | 23 + .../test/evidence/ta_endorsements.json | 11 - .../test/evidence/unmatched_endorsements.json | 12 - scheme/parsec-cca/test_vars.go | 12 + scheme/parsec-tpm/Makefile | 6 +- scheme/parsec-tpm/README.md | 30 - scheme/parsec-tpm/common.go | 9 - scheme/parsec-tpm/corim.go | 103 +++ scheme/parsec-tpm/corim_extractor.go | 190 ------ scheme/parsec-tpm/corim_test.go | 65 ++ scheme/parsec-tpm/corim_test_vectors.go | 43 -- scheme/parsec-tpm/endorsement_handler.go | 57 -- scheme/parsec-tpm/endorsement_handler_test.go | 146 ----- scheme/parsec-tpm/evidence_handler.go | 293 --------- scheme/parsec-tpm/evidence_handler_test.go | 225 ------- scheme/parsec-tpm/plugin/Makefile | 16 +- scheme/parsec-tpm/plugin/combined/Makefile | 11 - scheme/parsec-tpm/plugin/combined/main.go | 16 - .../plugin/endorsement-handler/Makefile | 11 - .../plugin/evidence-handler/Makefile | 11 - .../plugin/evidence-handler/main.go | 14 - .../plugin/{endorsement-handler => }/main.go | 4 +- .../parsec-tpm/plugin/store-handler/Makefile | 11 - .../parsec-tpm/plugin/store-handler/main.go | 14 - scheme/parsec-tpm/scheme.go | 296 ++++++++- scheme/parsec-tpm/store_handler.go | 129 ---- scheme/parsec-tpm/store_handler_test.go | 89 --- .../test/corim/build-test-vectors.sh | 33 - .../test/corim/compile-endorsements.sh | 17 + ...bor => corim-parsec-tpm-bad-class-id.cbor} | Bin 388 -> 410 bytes ...bor => corim-parsec-tpm-bad-instance.cbor} | Bin 382 -> 404 bytes ...> corim-parsec-tpm-bad-multiple-keys.cbor} | Bin 582 -> 604 bytes ... => corim-parsec-tpm-bad-no-class-id.cbor} | Bin 392 -> 414 bytes ...bor => corim-parsec-tpm-bad-no-class.cbor} | Bin 379 -> 401 bytes .../corim-parsec-tpm-bad-no-digests.cbor | Bin 0 -> 213 bytes ... => corim-parsec-tpm-bad-no-instance.cbor} | Bin 362 -> 384 bytes .../corim/corim-parsec-tpm-bad-no-pcr.cbor | Bin 0 -> 389 bytes .../test/corim/corim-parsec-tpm-bad-pcr.cbor | Bin 0 -> 429 bytes .../test/corim/corim-parsec-tpm-valid.cbor | Bin 0 -> 819 bytes .../corim/src/ComidParsecTpmPcrsNoClass.json | 54 -- ...assIdType.json => comid-bad-class-id.json} | 0 ...tanceType.json => comid-bad-instance.json} | 0 ...Keys.json => comid-bad-multiple-keys.json} | 2 +- ...lassId.json => comid-bad-no-class-id.json} | 0 ...eyNoClass.json => comid-bad-no-class.json} | 0 ...Digests.json => comid-bad-no-digests.json} | 0 ...stance.json => comid-bad-no-instance.json} | 0 ...pmPcrsNoPCR.json => comid-bad-no-pcr.json} | 0 ...UnknownPCRType.json => comid-bad-pcr.json} | 0 ...Good.json => comid-parsec-tpm-refval.json} | 18 +- ...mKeyGood.json => comid-parsec-tpm-ta.json} | 6 +- .../{corimMini.json => corim-parsec-tpm.json} | 2 +- scheme/parsec-tpm/test/corim/src/corims.yaml | 25 + .../corim/submit-parsec-tpm-endorsements.sh | 6 + ...nsignedCorimMiniComidParsecTpmKeyGood.cbor | Bin 401 -> 0 bytes ...signedCorimMiniComidParsecTpmPcrsGood.cbor | Bin 371 -> 0 bytes ...nedCorimMiniComidParsecTpmPcrsNoClass.cbor | Bin 388 -> 0 bytes ...dCorimMiniComidParsecTpmPcrsNoDigests.cbor | Bin 191 -> 0 bytes ...ignedCorimMiniComidParsecTpmPcrsNoPCR.cbor | Bin 367 -> 0 bytes ...mMiniComidParsecTpmPcrsUnknownPCRType.cbor | Bin 407 -> 0 bytes .../test/evidence/bad_evidence.cbor | Bin 655 -> 0 bytes .../test/evidence/bad_key_endorsements.json | 9 - .../evidence/bad_key_header_endorsements.json | 9 - .../test/evidence/bad_key_private_key.json | 9 - .../test/evidence/bad_ta_endorsements.json | 9 - .../evidence/compile-parsec-tpm-evidence.sh | 9 + .../parsec-tpm/test/evidence/evidence1.cbor | Bin 661 -> 0 bytes .../parsec-tpm/test/evidence/extracted.json | 20 - .../match_pcr_digest_endorsements.json | 5 - .../test/evidence/matched_extracted.json | 20 - .../test/evidence/refval-endorsements.json | 10 - .../test/evidence/src/evidence.diag | 15 + .../evidence/submit-parsec-tpm-evidence.sh | 23 + .../test/evidence/ta_endorsements.json | 9 - .../unmatch_pcr_digest_endorsements.json | 4 - .../evidence/unmatch_pcr_endorsements.json | 3 - scheme/parsec-tpm/test_vars.go | 39 ++ scheme/psa-iot/Makefile | 3 - scheme/psa-iot/README.md | 36 - scheme/psa-iot/corim.go | 94 +++ scheme/psa-iot/corim_extractor.go | 164 ----- scheme/psa-iot/corim_test.go | 55 ++ scheme/psa-iot/endorsement_handler.go | 57 -- scheme/psa-iot/endorsement_handler_test.go | 128 ---- scheme/psa-iot/evidence_handler.go | 155 ----- scheme/psa-iot/evidence_handler_test.go | 177 ----- scheme/psa-iot/plugin/Makefile | 16 +- scheme/psa-iot/plugin/combined/Makefile | 11 - scheme/psa-iot/plugin/combined/main.go | 16 - .../plugin/endorsement-handler/Makefile | 11 - .../psa-iot/plugin/evidence-handler/Makefile | 11 - .../psa-iot/plugin/evidence-handler/main.go | 14 - .../plugin/{endorsement-handler => }/main.go | 4 +- scheme/psa-iot/plugin/store-handler/Makefile | 11 - scheme/psa-iot/plugin/store-handler/main.go | 14 - scheme/psa-iot/scheme.go | 293 ++++++++- scheme/psa-iot/store_handler.go | 64 -- scheme/psa-iot/store_handler_test.go | 84 --- .../psa-iot/test/corim/build-test-vectors.sh | 32 - .../test/corim/compile-endorsements.sh | 16 + ...NoImplID.cbor => corim-psa-bad-class.cbor} | Bin 386 -> 356 bytes .../test/corim/corim-psa-bad-instance.cbor | Bin 0 -> 355 bytes .../corim/corim-psa-bad-refval-instance.cbor | Bin 0 -> 286 bytes .../test/corim/corim-psa-bad-refval-mkey.cbor | Bin 0 -> 281 bytes .../test/corim/corim-psa-bad-refval-mval.cbor | Bin 0 -> 215 bytes .../test/corim/corim-psa-bad-ta-cert.cbor | Bin 0 -> 2469 bytes .../corim/corim-psa-bad-ta-no-instance.cbor | Bin 0 -> 335 bytes .../psa-iot/test/corim/corim-psa-valid.cbor | Bin 0 -> 1017 bytes .../test/corim/src/ComidPsaMultIak.json | 48 -- .../corim/src/ComidPsaRefValNoImplID.json | 52 -- .../test/corim/src/ComidPsaRefValNoMkey.json | 52 -- .../test/corim/src/ComidPsaRefValOne.cbor | Bin 228 -> 0 bytes .../test/corim/src/ComidPsaRefValThree.json | 81 --- ...kPubNoImplID.json => comid-bad-class.json} | 16 +- ...PubNoUeID.json => comid-bad-instance.json} | 21 +- ...tr.json => comid-bad-refval-instance.json} | 23 +- ...ValOne.json => comid-bad-refval-mkey.json} | 27 +- ...Digest.json => comid-bad-refval-mval.json} | 30 +- .../test/corim/src/comid-bad-ta-cert.json | 30 + .../corim/src/comid-bad-ta-no-instance.json} | 23 +- .../test/corim/src/comid-psa-refval.json} | 29 +- ...midPsaIakPubTwo.json => comid-psa-ta.json} | 17 +- scheme/psa-iot/test/corim/src/corim-psa.json | 4 + scheme/psa-iot/test/corim/src/corimMini.json | 4 - scheme/psa-iot/test/corim/src/corims.yaml | 21 + .../test/corim/submit-psa-iot-endorsements.sh | 6 + ...unsignedCorimMiniComidPsaIakPubNoUeID.cbor | Bin 374 -> 0 bytes .../unsignedCorimMiniComidPsaIakPubOne.cbor | Bin 413 -> 0 bytes .../unsignedCorimMiniComidPsaIakPubTwo.cbor | Bin 694 -> 0 bytes .../unsignedCorimMiniComidPsaMultIak.cbor | Bin 594 -> 0 bytes ...gnedCorimMiniComidPsaRefValMultDigest.cbor | Bin 321 -> 0 bytes ...signedCorimMiniComidPsaRefValNoImplID.cbor | Bin 257 -> 0 bytes ...unsignedCorimMiniComidPsaRefValNoMkey.cbor | Bin 238 -> 0 bytes .../unsignedCorimMiniComidPsaRefValOne.cbor | Bin 284 -> 0 bytes ...CorimMiniComidPsaRefValOnlyMandIDAttr.cbor | Bin 273 -> 0 bytes .../unsignedCorimMiniComidPsaRefValThree.cbor | Bin 473 -> 0 bytes .../test/token/compile-psa-evidence.sh | 4 + scheme/psa-iot/test/token/ec.p256.jwk | 9 + scheme/psa-iot/test/token/psa.good.cose | Bin 0 -> 546 bytes scheme/psa-iot/test/token/psa.good.json | 31 + .../test/token/submit-psa-iot-evidence.sh | 18 + scheme/psa-iot/test_vars.go | 33 + scheme/psa-iot/test_vectors.go | 51 -- scheme/riot/Makefile | 2 +- scheme/riot/corim.go | 64 ++ scheme/riot/corim_test.go | 40 ++ scheme/riot/evidence_handler.go | 220 ------- scheme/riot/evidence_handler_test.go | 49 -- scheme/riot/plugin/Makefile | 15 +- scheme/riot/plugin/combined/Makefile | 11 - scheme/riot/plugin/combined/main.go | 15 - scheme/riot/plugin/evidence-handler/Makefile | 11 - .../plugin/{evidence-handler => }/main.go | 4 +- scheme/riot/plugin/store-handler/Makefile | 11 - scheme/riot/plugin/store-handler/main.go | 14 - scheme/riot/scheme.go | 265 +++++++- scheme/riot/store_handler.go | 50 -- .../riot/test/corim/compile-endorsements.sh | 16 + .../corim-riot-bad-no-vendor.cbor} | Bin 1828 -> 1927 bytes .../test/corim/corim-riot-bad-refvals.cbor | Bin 0 -> 2049 bytes .../corim/corim-riot-bad-wrong-key-type.cbor | Bin 0 -> 323 bytes .../corim/corim-riot-bad-wrong-vendor.cbor | Bin 0 -> 1933 bytes scheme/riot/test/corim/corim-riot-valid.cbor | Bin 0 -> 1945 bytes .../test/corim/src/comid-bad-no-vendor.json | 22 + .../test/corim/src/comid-bad-refvals.json | 46 ++ .../corim/src/comid-bad-wrong-key-type.json | 23 + .../corim/src/comid-bad-wrong-vendor.json | 23 + scheme/riot/test/corim/src/comid-riot-ta.json | 23 + scheme/riot/test/corim/src/corim-riot.json | 4 + scheme/riot/test/corim/src/corims.yaml | 14 + .../test/corim/submit-riot-endorsements.sh | 6 + .../evidence.pem} | 0 .../test/evidence/submit-riot-evidence.sh | 23 + scheme/riot/test_vars.go | 24 + scheme/sevsnp/Makefile | 2 +- scheme/sevsnp/README.md | 68 -- scheme/sevsnp/common.go | 207 ------ scheme/sevsnp/corim.go | 111 ++++ scheme/sevsnp/corim_test.go | 41 ++ scheme/sevsnp/endorsement_handler.go | 64 -- scheme/sevsnp/endorsement_handler_test.go | 46 -- scheme/sevsnp/evidence_handler.go | 564 ---------------- scheme/sevsnp/evidence_handler_test.go | 177 ----- scheme/sevsnp/extractor.go | 66 -- scheme/sevsnp/plugin/Makefile | 16 +- scheme/sevsnp/plugin/combined/Makefile | 11 - scheme/sevsnp/plugin/combined/main.go | 16 - .../plugin/endorsement-handler/Makefile | 11 - .../sevsnp/plugin/evidence-handler/Makefile | 11 - scheme/sevsnp/plugin/evidence-handler/main.go | 14 - .../plugin/{endorsement-handler => }/main.go | 4 +- scheme/sevsnp/plugin/store-handler/Makefile | 11 - scheme/sevsnp/plugin/store-handler/main.go | 14 - scheme/sevsnp/scheme.go | 614 +++++++++++++++++- scheme/sevsnp/store_handler.go | 199 ------ scheme/sevsnp/store_handler_test.go | 97 --- .../sevsnp/test/corim/compile-endorsements.sh | 17 + .../corim/corim-sevsnp-bad-refval-key.cbor | Bin 0 -> 237 bytes .../corim/corim-sevsnp-bad-refval-no-key.cbor | Bin 0 -> 224 bytes .../corim/corim-sevsnp-bad-ta-no-model.cbor | Bin 0 -> 2426 bytes .../corim/corim-sevsnp-bad-ta-no-vendor.cbor | Bin 0 -> 2413 bytes .../sevsnp/test/corim/corim-sevsnp-valid.cbor | Bin 0 -> 3112 bytes .../test/corim/src/comid-bad-refval-key.json | 38 ++ .../corim/src/comid-bad-refval-no-key.json | 34 + .../test/corim/src/comid-bad-ta-no-model.json | 22 + .../corim/src/comid-bad-ta-no-vendor.json | 22 + .../test/corim/src/comid-sevsnp-refval.json | 241 +++++++ .../test/corim/src/comid-sevsnp-ta.json | 23 + .../sevsnp/test/corim/src/corim-sevsnp.json | 4 + scheme/sevsnp/test/corim/src/corims.yaml | 15 + .../test/corim/submit-sevsnp-endorsements.sh | 6 + .../test/corim/unsignedCorimSevSnp.cbor | Bin 2761 -> 0 bytes .../test/{ => evidence}/sevsnp-ratsd-token | 0 .../{ => evidence}/sevsnp-tsm-report.cbor | Bin .../{ => evidence}/sevsnp-tsm-report.json | 0 .../test/evidence/submit-sevsnp-evidence.sh | 33 + scheme/sevsnp/test/refval-endorsement.json | 272 -------- scheme/sevsnp/test/refval-prov.cbor | Bin 5789 -> 0 bytes scheme/sevsnp/test/ta-endorsement-bad.json | 19 - scheme/sevsnp/test/ta-endorsement.json | 19 - scheme/sevsnp/test/ta-prov.json | 25 - scheme/sevsnp/test_vars.go | 24 + scheme/sevsnp/test_vectors.go | 10 - scheme/tpm-enacttrust/corim.go | 103 +++ scheme/tpm-enacttrust/corim_test.go | 55 ++ scheme/tpm-enacttrust/endorsement_handler.go | 57 -- .../endorsement_handler_test.go | 118 ---- scheme/tpm-enacttrust/endorsements.go | 55 -- scheme/tpm-enacttrust/evidence_handler.go | 164 ----- .../tpm-enacttrust/evidence_handler_test.go | 130 ---- scheme/tpm-enacttrust/extractor.go | 129 ---- scheme/tpm-enacttrust/instanceattributes.go | 30 - scheme/tpm-enacttrust/plugin/Makefile | 16 +- .../tpm-enacttrust/plugin/combined/Makefile | 11 - scheme/tpm-enacttrust/plugin/combined/main.go | 16 - .../plugin/endorsement-handler/Makefile | 11 - .../plugin/evidence-handler/Makefile | 11 - .../plugin/evidence-handler/main.go | 14 - .../plugin/{endorsement-handler => }/main.go | 4 +- .../plugin/store-handler/Makefile | 11 - .../plugin/store-handler/main.go | 14 - scheme/tpm-enacttrust/scheme.go | 186 +++++- scheme/tpm-enacttrust/store_handler.go | 122 ---- scheme/tpm-enacttrust/store_handler_test.go | 47 -- scheme/tpm-enacttrust/swcompattributes.go | 32 - .../test/corim/build-test-vectors.sh | 30 - .../test/corim/compile-endorsements.sh | 16 + .../corim/corim-enacttrust-bad-class.cbor | Bin 0 -> 248 bytes .../corim/corim-enacttrust-bad-instance.cbor | Bin 0 -> 245 bytes ...corim-enacttrust-bad-multiple-digests.cbor | Bin 0 -> 262 bytes ...> corim-enacttrust-bad-multiple-keys.cbor} | Bin 526 -> 548 bytes ...-enacttrust-bad-multiple-measurements.cbor | Bin 0 -> 267 bytes .../corim/corim-enacttrust-bad-no-digest.cbor | Bin 0 -> 214 bytes .../corim-enacttrust-bad-no-instance.cbor | Bin 0 -> 264 bytes .../test/corim/corim-enacttrust-valid.cbor | Bin 0 -> 507 bytes .../test/corim/src/comid-bad-class.json | 43 ++ ...stBadInst.json => comid-bad-instance.json} | 0 ...t.json => comid-bad-multiple-digests.json} | 0 ...Mult.json => comid-bad-multiple-keys.json} | 0 ...n => comid-bad-multiple-measurements.json} | 0 ...NoDigest.json => comid-bad-no-digest.json} | 0 ...NoInst.json => comid-bad-no-instance.json} | 0 ...nOne.json => comid-enacttrust-refval.json} | 6 +- ...ustAKOne.json => comid-enacttrust-ta.json} | 6 +- .../{corimMini.json => corim-enacttrust.json} | 2 +- .../tpm-enacttrust/test/corim/src/corims.yaml | 21 + .../corim/submit-enacttrust-endorsements.sh | 6 + ...dCorimMiniComidTpmEnactTrustAKBadInst.cbor | Bin 364 -> 0 bytes ...ignedCorimMiniComidTpmEnactTrustAKOne.cbor | Bin 345 -> 0 bytes ...nedCorimMiniComidTpmEnactTrustBadInst.cbor | Bin 223 -> 0 bytes ...dCorimMiniComidTpmEnactTrustGoldenOne.cbor | Bin 204 -> 0 bytes ...dCorimMiniComidTpmEnactTrustGoldenTwo.cbor | Bin 245 -> 0 bytes ...CorimMiniComidTpmEnactTrustMultDigest.cbor | Bin 240 -> 0 bytes ...edCorimMiniComidTpmEnactTrustNoDigest.cbor | Bin 192 -> 0 bytes ...gnedCorimMiniComidTpmEnactTrustNoInst.cbor | Bin 242 -> 0 bytes .../test/{tokens => evidence}/Makefile | 0 .../test/{tokens => evidence}/basic.json | 0 .../test/{tokens => evidence}/basic.token | Bin .../evidence/submit-enacattrust-evidence.sh | 18 + scheme/tpm-enacttrust/test/refval.json | 10 - scheme/tpm-enacttrust/test/trustanchor.json | 8 - scheme/tpm-enacttrust/test_vars.go | 33 + scheme/tpm-enacttrust/test_vectors.go | 34 - scripts/generate-corims | 403 ++++++++++++ scripts/generate-test-vector-embeds | 186 ++++++ scripts/get-veraison-version | 2 + tools.go | 2 + verification/cmd/verification-service/main.go | 6 +- verification/sessionmanager/common_test.go | 3 +- verification/sessionmanager/memcached.go | 6 +- .../memcached_fakeserver_test.go | 10 +- verification/sessionmanager/memcached_test.go | 3 +- verification/sessionmanager/new.go | 5 +- vts/appraisal/appraisal.go | 90 --- vts/appraisal/context.go | 214 ++++++ vts/appraisal/evidence.go | 33 + vts/cmd/vts-service/config-docker.yaml | 19 +- vts/cmd/vts-service/config.yaml | 14 +- vts/cmd/vts-service/main.go | 79 +-- vts/coservsigner/coservsigner_cose_test.go | 2 + vts/earsigner/earsigner_jwt.go | 8 +- vts/earsigner/iearsigner.go | 6 +- vts/earsigner/keyloader.go | 6 +- vts/earsigner/keyloader_aws.go | 8 +- vts/earsigner/keyloader_file.go | 8 +- vts/policymanager/mocks/iagent.go | 11 +- vts/policymanager/mocks/ibackend.go | 4 +- vts/policymanager/policymanager.go | 30 +- vts/policymanager/policymanager_test.go | 97 ++- vts/store/store.go | 57 ++ vts/trustedservices/itrustedservices.go | 12 +- vts/trustedservices/trustedservices_grpc.go | 584 +++++++++-------- 632 files changed, 10052 insertions(+), 13758 deletions(-) create mode 100644 deployments/docker/src/corim-store-config.yaml.template create mode 100644 deployments/native/config/corim-store.yaml.template delete mode 100644 handler/endorsement.go delete mode 100644 handler/endorsement_rpc.go delete mode 100644 handler/evidence_rpc.go delete mode 100644 handler/idecoder_manager.go delete mode 100644 handler/iendorsementhandler.go delete mode 100644 handler/ievidencehandler.go create mode 100644 handler/ischemehandler.go create mode 100644 handler/ischemeimplementation.go delete mode 100644 handler/istorehandler.go create mode 100644 handler/scheme_rpc.go create mode 100644 handler/schemedescriptor.go create mode 100644 handler/schemeimplementationwrapper.go delete mode 100644 handler/store_rpc.go rename policy/test/inputs/{enacttrust-endorsements.json => empty-endorsements.json} (100%) create mode 100644 proto/scheme.pb.go create mode 100644 proto/scheme.pb.json.go create mode 100644 proto/scheme.proto delete mode 100644 scheme/MIGRATING.md delete mode 100644 scheme/amd-kds-coserv/plugin/combined/Makefile delete mode 100644 scheme/amd-kds-coserv/plugin/combined/main.go delete mode 100644 scheme/amd-kds-coserv/plugin/coserv-handler/Makefile rename scheme/amd-kds-coserv/plugin/{coserv-handler => }/main.go (83%) delete mode 100644 scheme/arm-cca/README.md create mode 100644 scheme/arm-cca/corim.go delete mode 100644 scheme/arm-cca/corim_extractor.go create mode 100644 scheme/arm-cca/corim_test.go delete mode 100644 scheme/arm-cca/endorsement_handler.go delete mode 100644 scheme/arm-cca/endorsement_handler_test.go delete mode 100644 scheme/arm-cca/evidence_handler.go delete mode 100644 scheme/arm-cca/evidence_handler_test.go delete mode 100644 scheme/arm-cca/platform.go delete mode 100644 scheme/arm-cca/plugin/combined/Makefile delete mode 100644 scheme/arm-cca/plugin/combined/main.go delete mode 100644 scheme/arm-cca/plugin/endorsement-handler/Makefile delete mode 100644 scheme/arm-cca/plugin/endorsement-handler/main.go delete mode 100644 scheme/arm-cca/plugin/evidence-handler/Makefile rename scheme/arm-cca/plugin/{evidence-handler => }/main.go (61%) delete mode 100644 scheme/arm-cca/plugin/store-handler/Makefile delete mode 100644 scheme/arm-cca/plugin/store-handler/main.go delete mode 100644 scheme/arm-cca/realm.go delete mode 100644 scheme/arm-cca/store_handler.go delete mode 100644 scheme/arm-cca/store_handler_test.go delete mode 100755 scheme/arm-cca/test/corim/build-test-vectors.sh create mode 100755 scheme/arm-cca/test/corim/compile-endorsements.sh create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-no-class.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-instance.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-mkey.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-digests.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-mkey.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-raw-value.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-cert.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-instance.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-no-instance.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-platform-valid.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-realm-bad-instance.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-realm-bad-no-instance.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-realm-bad-no-integ-regs.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-realm-bad-no-raw-value.cbor create mode 100644 scheme/arm-cca/test/corim/corim-cca-realm-valid.cbor create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-no-class.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-instance.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-mkey.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-digests.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-mkey.json rename scheme/{parsec-cca/test/corim/src/ComidParsecCcaRefValOne.json => arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-raw-value.json} (51%) create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-cert.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-instance.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-no-instance.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-refval.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-platform-ta.json rename scheme/arm-cca/test/corim/src/{comidCcaRealmNoInstance.json => comid-cca-realm-bad-instance.json} (52%) create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-instance.json create mode 100644 scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-integ-regs.json rename scheme/arm-cca/test/corim/src/{comidCcaRealmNoClass.json => comid-cca-realm-bad-no-raw-value.json} (57%) rename scheme/arm-cca/test/corim/src/{comidCcaRealmInvalidClass.json => comid-cca-realm-refval.json} (52%) delete mode 100644 scheme/arm-cca/test/corim/src/comidCcaRealm.json delete mode 100644 scheme/arm-cca/test/corim/src/comidCcaRealmInvalidInstance.json delete mode 100644 scheme/arm-cca/test/corim/src/comidCcaRefValOne.json create mode 100644 scheme/arm-cca/test/corim/src/corim-cca-platform.json create mode 100644 scheme/arm-cca/test/corim/src/corim-cca-realm.json delete mode 100644 scheme/arm-cca/test/corim/src/corimCca.json delete mode 100644 scheme/arm-cca/test/corim/src/corimCcaNoProfile.json delete mode 100644 scheme/arm-cca/test/corim/src/corimCcaRealm.json create mode 100644 scheme/arm-cca/test/corim/src/platform-corims.yaml create mode 100644 scheme/arm-cca/test/corim/src/realm-corims.yaml create mode 100755 scheme/arm-cca/test/corim/submit-arm-cca-endorsements.sh delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValFour.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValOne.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValFour.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValOne.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealm.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidClass.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidInstance.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor delete mode 100644 scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor create mode 100644 scheme/arm-cca/test/evidence/cca-good.cbor delete mode 100644 scheme/arm-cca/test/evidence/cca-token.cbor delete mode 100644 scheme/arm-cca/test/evidence/cca-token.json create mode 100755 scheme/arm-cca/test/evidence/compile-cca-evidence.sh delete mode 100644 scheme/arm-cca/test/evidence/extracted-claims.json delete mode 100644 scheme/arm-cca/test/evidence/extracted.json create mode 100644 scheme/arm-cca/test/evidence/src/cca-good.json create mode 100644 scheme/arm-cca/test/evidence/src/ec.p256.jwk create mode 100644 scheme/arm-cca/test/evidence/src/ec.p384.jwk create mode 100755 scheme/arm-cca/test/evidence/submit-arm-cca-evidence.sh delete mode 100644 scheme/arm-cca/test/platform/endorsements.json delete mode 100644 scheme/arm-cca/test/platform/invalid-key-ta-endorsements.json delete mode 100644 scheme/arm-cca/test/platform/mismatch-cfg-endorsements.json delete mode 100644 scheme/arm-cca/test/platform/mismatch-refval-endorsements.json delete mode 100644 scheme/arm-cca/test/platform/mult-endorsements.json delete mode 100644 scheme/arm-cca/test/platform/refval-endorsements.json delete mode 100644 scheme/arm-cca/test/platform/ta-endorsements.json delete mode 100644 scheme/arm-cca/test/platform/ta-integ-endorsements.json delete mode 100644 scheme/arm-cca/test/realm/match-endorsements.json delete mode 100644 scheme/arm-cca/test/realm/no-realm-endorsements.json delete mode 100644 scheme/arm-cca/test/realm/no-rem-endorsements.json delete mode 100644 scheme/arm-cca/test/realm/no-rpv-endorsements.json delete mode 100644 scheme/arm-cca/test/realm/rim-mismatch-endorsements.json create mode 100644 scheme/arm-cca/test_vars.go delete mode 100644 scheme/arm-cca/test_vectors.go delete mode 100644 scheme/common/arm/Makefile delete mode 100644 scheme/common/arm/coservrepackager.go delete mode 100644 scheme/common/arm/handlers.go delete mode 100644 scheme/common/arm/lookup.go delete mode 100644 scheme/common/arm/platform/classattributes.go delete mode 100644 scheme/common/arm/platform/imeasurement.go delete mode 100644 scheme/common/arm/platform/instanceattributes.go delete mode 100644 scheme/common/arm/platform/swcompattributes.go delete mode 100644 scheme/common/arm/platform/swcompattributes_test.go delete mode 100644 scheme/common/cca/Makefile delete mode 100644 scheme/common/cca/platform/cca_ssd_extractor.go delete mode 100644 scheme/common/cca/platform/ccaplatformconfigid.go delete mode 100644 scheme/common/cca/realm/realm_attributes.go delete mode 100644 scheme/common/cca/realm/realm_classattributes.go delete mode 100644 scheme/common/cca/realm/realm_extractor.go delete mode 100644 scheme/common/cca/realm/realm_handlers.go delete mode 100644 scheme/common/cca/realm/realm_instanceattributes.go delete mode 100644 scheme/common/cca/realm/realm_utils.go create mode 100644 scheme/common/corim.go delete mode 100644 scheme/common/iextractor.go delete mode 100755 scheme/common/scripts/gen-corim delete mode 100644 scheme/common/signedcorim_decoder.go delete mode 100644 scheme/common/unsignedcorim_decoder.go create mode 100644 scheme/common/util.go delete mode 100644 scheme/common/utils.go create mode 100644 scheme/example/Makefile create mode 100644 scheme/example/README.md create mode 100644 scheme/example/corim.go create mode 100644 scheme/example/plugin/Makefile create mode 100644 scheme/example/plugin/main.go create mode 100644 scheme/example/scheme.go delete mode 100644 scheme/nvidia-coserv/plugin/combined/Makefile delete mode 100644 scheme/nvidia-coserv/plugin/coserv-handler/Makefile delete mode 100644 scheme/nvidia-coserv/plugin/coserv-handler/main.go rename scheme/nvidia-coserv/plugin/{combined => }/main.go (83%) create mode 100644 scheme/parsec-cca/corim.go create mode 100644 scheme/parsec-cca/corim_test.go delete mode 100644 scheme/parsec-cca/corim_test_vectors.go delete mode 100644 scheme/parsec-cca/endorsement_handler.go delete mode 100644 scheme/parsec-cca/endorsement_handler_test.go delete mode 100644 scheme/parsec-cca/evidence_handler.go delete mode 100644 scheme/parsec-cca/evidence_handler_test.go delete mode 100644 scheme/parsec-cca/parsec_cca_extractor.go delete mode 100644 scheme/parsec-cca/plugin/combined/Makefile delete mode 100644 scheme/parsec-cca/plugin/combined/main.go delete mode 100644 scheme/parsec-cca/plugin/endorsement-handler/Makefile delete mode 100644 scheme/parsec-cca/plugin/evidence-handler/Makefile delete mode 100644 scheme/parsec-cca/plugin/evidence-handler/main.go rename scheme/parsec-cca/plugin/{endorsement-handler => }/main.go (61%) delete mode 100644 scheme/parsec-cca/plugin/store-handler/Makefile delete mode 100644 scheme/parsec-cca/plugin/store-handler/main.go delete mode 100644 scheme/parsec-cca/store_handler.go delete mode 100644 scheme/parsec-cca/store_handler_test.go delete mode 100755 scheme/parsec-cca/test/corim/build-test-vectors.sh create mode 100755 scheme/parsec-cca/test/corim/compile-endorsements.sh create mode 100644 scheme/parsec-cca/test/corim/corim-parsec-cca-valid.cbor delete mode 100644 scheme/parsec-cca/test/corim/src/ComidParsecCcaMultRefVal.json create mode 100644 scheme/parsec-cca/test/corim/src/comid-parsec-cca-refval.json rename scheme/{psa-iot/test/corim/src/ComidPsaIakPubOne.json => parsec-cca/test/corim/src/comid-parsec-cca-ta.json} (53%) create mode 100644 scheme/parsec-cca/test/corim/src/corim-parsec-cca.json delete mode 100644 scheme/parsec-cca/test/corim/src/corimParsecCca.json create mode 100644 scheme/parsec-cca/test/corim/src/corims.yaml create mode 100755 scheme/parsec-cca/test/corim/submit-parsec-cca-endorsements.sh delete mode 100644 scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaMultRefVal.cbor delete mode 100644 scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor delete mode 100644 scheme/parsec-cca/test/evidence/bad_evidence.cbor delete mode 100644 scheme/parsec-cca/test/evidence/bad_key_endorsements.json delete mode 100644 scheme/parsec-cca/test/evidence/bad_key_header_endorsements.json delete mode 100644 scheme/parsec-cca/test/evidence/bad_key_private_key.json create mode 100755 scheme/parsec-cca/test/evidence/compile-parsec-cca-evidence.sh mode change 100755 => 100644 scheme/parsec-cca/test/evidence/evidence.cbor delete mode 100755 scheme/parsec-cca/test/evidence/extracted.json delete mode 100644 scheme/parsec-cca/test/evidence/mismatch_cfg_refval_endorsements.json delete mode 100644 scheme/parsec-cca/test/evidence/mismatch_swcomp_refval_endorsements.json delete mode 100644 scheme/parsec-cca/test/evidence/refval_endorsement.json delete mode 100644 scheme/parsec-cca/test/evidence/refval_endorsements.json create mode 100644 scheme/parsec-cca/test/evidence/src/cca-claims.json.template create mode 100644 scheme/parsec-cca/test/evidence/src/ec.p256.jwk create mode 100644 scheme/parsec-cca/test/evidence/src/ec.p384.jwk create mode 100644 scheme/parsec-cca/test/evidence/src/kat.diag create mode 100755 scheme/parsec-cca/test/evidence/submit-parsec-cca-evidence.sh delete mode 100644 scheme/parsec-cca/test/evidence/ta_endorsements.json delete mode 100644 scheme/parsec-cca/test/evidence/unmatched_endorsements.json create mode 100644 scheme/parsec-cca/test_vars.go delete mode 100644 scheme/parsec-tpm/README.md delete mode 100644 scheme/parsec-tpm/common.go create mode 100644 scheme/parsec-tpm/corim.go delete mode 100644 scheme/parsec-tpm/corim_extractor.go create mode 100644 scheme/parsec-tpm/corim_test.go delete mode 100644 scheme/parsec-tpm/corim_test_vectors.go delete mode 100644 scheme/parsec-tpm/endorsement_handler.go delete mode 100644 scheme/parsec-tpm/endorsement_handler_test.go delete mode 100644 scheme/parsec-tpm/evidence_handler.go delete mode 100644 scheme/parsec-tpm/evidence_handler_test.go delete mode 100644 scheme/parsec-tpm/plugin/combined/Makefile delete mode 100644 scheme/parsec-tpm/plugin/combined/main.go delete mode 100644 scheme/parsec-tpm/plugin/endorsement-handler/Makefile delete mode 100644 scheme/parsec-tpm/plugin/evidence-handler/Makefile delete mode 100644 scheme/parsec-tpm/plugin/evidence-handler/main.go rename scheme/parsec-tpm/plugin/{endorsement-handler => }/main.go (61%) delete mode 100644 scheme/parsec-tpm/plugin/store-handler/Makefile delete mode 100644 scheme/parsec-tpm/plugin/store-handler/main.go delete mode 100644 scheme/parsec-tpm/store_handler.go delete mode 100644 scheme/parsec-tpm/store_handler_test.go delete mode 100755 scheme/parsec-tpm/test/corim/build-test-vectors.sh create mode 100755 scheme/parsec-tpm/test/corim/compile-endorsements.sh rename scheme/parsec-tpm/test/corim/{unsignedCorimMiniComidParsecTpmKeyUnknownClassIdType.cbor => corim-parsec-tpm-bad-class-id.cbor} (83%) rename scheme/parsec-tpm/test/corim/{unsignedCorimMiniComidParsecTpmKeyUnknownInstanceType.cbor => corim-parsec-tpm-bad-instance.cbor} (82%) rename scheme/parsec-tpm/test/corim/{unsignedCorimMiniComidParsecTpmKeyManyKeys.cbor => corim-parsec-tpm-bad-multiple-keys.cbor} (77%) rename scheme/parsec-tpm/test/corim/{unsignedCorimMiniComidParsecTpmKeyNoClassId.cbor => corim-parsec-tpm-bad-no-class-id.cbor} (83%) rename scheme/parsec-tpm/test/corim/{unsignedCorimMiniComidParsecTpmKeyNoClass.cbor => corim-parsec-tpm-bad-no-class.cbor} (82%) create mode 100644 scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-digests.cbor rename scheme/parsec-tpm/test/corim/{unsignedCorimMiniComidParsecTpmKeyNoInstance.cbor => corim-parsec-tpm-bad-no-instance.cbor} (82%) create mode 100644 scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-pcr.cbor create mode 100644 scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-pcr.cbor create mode 100644 scheme/parsec-tpm/test/corim/corim-parsec-tpm-valid.cbor delete mode 100644 scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoClass.json rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyUnknownClassIdType.json => comid-bad-class-id.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyUnknownInstanceType.json => comid-bad-instance.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyManyKeys.json => comid-bad-multiple-keys.json} (97%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyNoClassId.json => comid-bad-no-class-id.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyNoClass.json => comid-bad-no-class.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmPcrsNoDigests.json => comid-bad-no-digests.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyNoInstance.json => comid-bad-no-instance.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmPcrsNoPCR.json => comid-bad-no-pcr.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmPcrsUnknownPCRType.json => comid-bad-pcr.json} (100%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmPcrsGood.json => comid-parsec-tpm-refval.json} (69%) rename scheme/parsec-tpm/test/corim/src/{ComidParsecTpmKeyGood.json => comid-parsec-tpm-ta.json} (76%) rename scheme/parsec-tpm/test/corim/src/{corimMini.json => corim-parsec-tpm.json} (54%) create mode 100644 scheme/parsec-tpm/test/corim/src/corims.yaml create mode 100755 scheme/parsec-tpm/test/corim/submit-parsec-tpm-endorsements.sh delete mode 100644 scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyGood.cbor delete mode 100644 scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor delete mode 100644 scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoClass.cbor delete mode 100644 scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor delete mode 100644 scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoPCR.cbor delete mode 100644 scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor delete mode 100644 scheme/parsec-tpm/test/evidence/bad_evidence.cbor delete mode 100644 scheme/parsec-tpm/test/evidence/bad_key_endorsements.json delete mode 100644 scheme/parsec-tpm/test/evidence/bad_key_header_endorsements.json delete mode 100644 scheme/parsec-tpm/test/evidence/bad_key_private_key.json delete mode 100644 scheme/parsec-tpm/test/evidence/bad_ta_endorsements.json create mode 100755 scheme/parsec-tpm/test/evidence/compile-parsec-tpm-evidence.sh delete mode 100644 scheme/parsec-tpm/test/evidence/evidence1.cbor delete mode 100644 scheme/parsec-tpm/test/evidence/extracted.json delete mode 100644 scheme/parsec-tpm/test/evidence/match_pcr_digest_endorsements.json delete mode 100644 scheme/parsec-tpm/test/evidence/matched_extracted.json delete mode 100644 scheme/parsec-tpm/test/evidence/refval-endorsements.json create mode 100644 scheme/parsec-tpm/test/evidence/src/evidence.diag create mode 100755 scheme/parsec-tpm/test/evidence/submit-parsec-tpm-evidence.sh delete mode 100644 scheme/parsec-tpm/test/evidence/ta_endorsements.json delete mode 100644 scheme/parsec-tpm/test/evidence/unmatch_pcr_digest_endorsements.json delete mode 100644 scheme/parsec-tpm/test/evidence/unmatch_pcr_endorsements.json create mode 100644 scheme/parsec-tpm/test_vars.go delete mode 100644 scheme/psa-iot/README.md create mode 100644 scheme/psa-iot/corim.go delete mode 100644 scheme/psa-iot/corim_extractor.go create mode 100644 scheme/psa-iot/corim_test.go delete mode 100644 scheme/psa-iot/endorsement_handler.go delete mode 100644 scheme/psa-iot/endorsement_handler_test.go delete mode 100644 scheme/psa-iot/evidence_handler.go delete mode 100644 scheme/psa-iot/evidence_handler_test.go delete mode 100644 scheme/psa-iot/plugin/combined/Makefile delete mode 100644 scheme/psa-iot/plugin/combined/main.go delete mode 100644 scheme/psa-iot/plugin/endorsement-handler/Makefile delete mode 100644 scheme/psa-iot/plugin/evidence-handler/Makefile delete mode 100644 scheme/psa-iot/plugin/evidence-handler/main.go rename scheme/psa-iot/plugin/{endorsement-handler => }/main.go (61%) delete mode 100644 scheme/psa-iot/plugin/store-handler/Makefile delete mode 100644 scheme/psa-iot/plugin/store-handler/main.go delete mode 100644 scheme/psa-iot/store_handler.go delete mode 100644 scheme/psa-iot/store_handler_test.go delete mode 100755 scheme/psa-iot/test/corim/build-test-vectors.sh create mode 100755 scheme/psa-iot/test/corim/compile-endorsements.sh rename scheme/psa-iot/test/corim/{unsignedCorimMiniComidPsaIakPubNoImplID.cbor => corim-psa-bad-class.cbor} (56%) create mode 100644 scheme/psa-iot/test/corim/corim-psa-bad-instance.cbor create mode 100644 scheme/psa-iot/test/corim/corim-psa-bad-refval-instance.cbor create mode 100644 scheme/psa-iot/test/corim/corim-psa-bad-refval-mkey.cbor create mode 100644 scheme/psa-iot/test/corim/corim-psa-bad-refval-mval.cbor create mode 100644 scheme/psa-iot/test/corim/corim-psa-bad-ta-cert.cbor create mode 100644 scheme/psa-iot/test/corim/corim-psa-bad-ta-no-instance.cbor create mode 100644 scheme/psa-iot/test/corim/corim-psa-valid.cbor delete mode 100644 scheme/psa-iot/test/corim/src/ComidPsaMultIak.json delete mode 100644 scheme/psa-iot/test/corim/src/ComidPsaRefValNoImplID.json delete mode 100644 scheme/psa-iot/test/corim/src/ComidPsaRefValNoMkey.json delete mode 100644 scheme/psa-iot/test/corim/src/ComidPsaRefValOne.cbor delete mode 100644 scheme/psa-iot/test/corim/src/ComidPsaRefValThree.json rename scheme/psa-iot/test/corim/src/{ComidPsaIakPubNoImplID.json => comid-bad-class.json} (74%) rename scheme/psa-iot/test/corim/src/{ComidPsaIakPubNoUeID.json => comid-bad-instance.json} (59%) rename scheme/psa-iot/test/corim/src/{ComidPsaRefValOnlyMandIDAttr.json => comid-bad-refval-instance.json} (67%) rename scheme/psa-iot/test/corim/src/{ComidPsaRefValOne.json => comid-bad-refval-mkey.json} (75%) rename scheme/psa-iot/test/corim/src/{ComidPsaRefValMultDigest.json => comid-bad-refval-mval.json} (54%) create mode 100644 scheme/psa-iot/test/corim/src/comid-bad-ta-cert.json rename scheme/{tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKBadInst.json => psa-iot/test/corim/src/comid-bad-ta-no-instance.json} (56%) rename scheme/{arm-cca/test/corim/src/comidCcaRefValFour.json => psa-iot/test/corim/src/comid-psa-refval.json} (75%) rename scheme/psa-iot/test/corim/src/{ComidPsaIakPubTwo.json => comid-psa-ta.json} (77%) create mode 100644 scheme/psa-iot/test/corim/src/corim-psa.json delete mode 100644 scheme/psa-iot/test/corim/src/corimMini.json create mode 100644 scheme/psa-iot/test/corim/src/corims.yaml create mode 100755 scheme/psa-iot/test/corim/submit-psa-iot-endorsements.sh delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoUeID.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaMultIak.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValMultDigest.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoMkey.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOne.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor delete mode 100644 scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValThree.cbor create mode 100755 scheme/psa-iot/test/token/compile-psa-evidence.sh create mode 100644 scheme/psa-iot/test/token/ec.p256.jwk create mode 100644 scheme/psa-iot/test/token/psa.good.cose create mode 100644 scheme/psa-iot/test/token/psa.good.json create mode 100755 scheme/psa-iot/test/token/submit-psa-iot-evidence.sh create mode 100644 scheme/psa-iot/test_vars.go delete mode 100644 scheme/psa-iot/test_vectors.go create mode 100644 scheme/riot/corim.go create mode 100644 scheme/riot/corim_test.go delete mode 100644 scheme/riot/evidence_handler.go delete mode 100644 scheme/riot/evidence_handler_test.go delete mode 100644 scheme/riot/plugin/combined/Makefile delete mode 100644 scheme/riot/plugin/combined/main.go delete mode 100644 scheme/riot/plugin/evidence-handler/Makefile rename scheme/riot/plugin/{evidence-handler => }/main.go (60%) delete mode 100644 scheme/riot/plugin/store-handler/Makefile delete mode 100644 scheme/riot/plugin/store-handler/main.go delete mode 100644 scheme/riot/store_handler.go create mode 100755 scheme/riot/test/corim/compile-endorsements.sh rename scheme/riot/test/{TrustAnchor.pem => corim/corim-riot-bad-no-vendor.cbor} (91%) create mode 100644 scheme/riot/test/corim/corim-riot-bad-refvals.cbor create mode 100644 scheme/riot/test/corim/corim-riot-bad-wrong-key-type.cbor create mode 100644 scheme/riot/test/corim/corim-riot-bad-wrong-vendor.cbor create mode 100644 scheme/riot/test/corim/corim-riot-valid.cbor create mode 100644 scheme/riot/test/corim/src/comid-bad-no-vendor.json create mode 100644 scheme/riot/test/corim/src/comid-bad-refvals.json create mode 100644 scheme/riot/test/corim/src/comid-bad-wrong-key-type.json create mode 100644 scheme/riot/test/corim/src/comid-bad-wrong-vendor.json create mode 100644 scheme/riot/test/corim/src/comid-riot-ta.json create mode 100644 scheme/riot/test/corim/src/corim-riot.json create mode 100644 scheme/riot/test/corim/src/corims.yaml create mode 100755 scheme/riot/test/corim/submit-riot-endorsements.sh rename scheme/riot/test/{DeviceCerts.pem => evidence/evidence.pem} (100%) create mode 100755 scheme/riot/test/evidence/submit-riot-evidence.sh create mode 100644 scheme/riot/test_vars.go delete mode 100644 scheme/sevsnp/README.md delete mode 100644 scheme/sevsnp/common.go create mode 100644 scheme/sevsnp/corim.go create mode 100644 scheme/sevsnp/corim_test.go delete mode 100644 scheme/sevsnp/endorsement_handler.go delete mode 100644 scheme/sevsnp/endorsement_handler_test.go delete mode 100644 scheme/sevsnp/evidence_handler.go delete mode 100644 scheme/sevsnp/evidence_handler_test.go delete mode 100644 scheme/sevsnp/extractor.go delete mode 100644 scheme/sevsnp/plugin/combined/Makefile delete mode 100644 scheme/sevsnp/plugin/combined/main.go delete mode 100644 scheme/sevsnp/plugin/endorsement-handler/Makefile delete mode 100644 scheme/sevsnp/plugin/evidence-handler/Makefile delete mode 100644 scheme/sevsnp/plugin/evidence-handler/main.go rename scheme/sevsnp/plugin/{endorsement-handler => }/main.go (61%) delete mode 100644 scheme/sevsnp/plugin/store-handler/Makefile delete mode 100644 scheme/sevsnp/plugin/store-handler/main.go delete mode 100644 scheme/sevsnp/store_handler.go delete mode 100644 scheme/sevsnp/store_handler_test.go create mode 100755 scheme/sevsnp/test/corim/compile-endorsements.sh create mode 100644 scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-key.cbor create mode 100644 scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-no-key.cbor create mode 100644 scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-model.cbor create mode 100644 scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-vendor.cbor create mode 100644 scheme/sevsnp/test/corim/corim-sevsnp-valid.cbor create mode 100644 scheme/sevsnp/test/corim/src/comid-bad-refval-key.json create mode 100644 scheme/sevsnp/test/corim/src/comid-bad-refval-no-key.json create mode 100644 scheme/sevsnp/test/corim/src/comid-bad-ta-no-model.json create mode 100644 scheme/sevsnp/test/corim/src/comid-bad-ta-no-vendor.json create mode 100644 scheme/sevsnp/test/corim/src/comid-sevsnp-refval.json create mode 100644 scheme/sevsnp/test/corim/src/comid-sevsnp-ta.json create mode 100644 scheme/sevsnp/test/corim/src/corim-sevsnp.json create mode 100644 scheme/sevsnp/test/corim/src/corims.yaml create mode 100755 scheme/sevsnp/test/corim/submit-sevsnp-endorsements.sh delete mode 100644 scheme/sevsnp/test/corim/unsignedCorimSevSnp.cbor rename scheme/sevsnp/test/{ => evidence}/sevsnp-ratsd-token (100%) rename scheme/sevsnp/test/{ => evidence}/sevsnp-tsm-report.cbor (100%) mode change 100755 => 100644 rename scheme/sevsnp/test/{ => evidence}/sevsnp-tsm-report.json (100%) create mode 100755 scheme/sevsnp/test/evidence/submit-sevsnp-evidence.sh delete mode 100644 scheme/sevsnp/test/refval-endorsement.json delete mode 100644 scheme/sevsnp/test/refval-prov.cbor delete mode 100644 scheme/sevsnp/test/ta-endorsement-bad.json delete mode 100644 scheme/sevsnp/test/ta-endorsement.json delete mode 100644 scheme/sevsnp/test/ta-prov.json create mode 100644 scheme/sevsnp/test_vars.go delete mode 100644 scheme/sevsnp/test_vectors.go create mode 100644 scheme/tpm-enacttrust/corim.go create mode 100644 scheme/tpm-enacttrust/corim_test.go delete mode 100644 scheme/tpm-enacttrust/endorsement_handler.go delete mode 100644 scheme/tpm-enacttrust/endorsement_handler_test.go delete mode 100644 scheme/tpm-enacttrust/endorsements.go delete mode 100644 scheme/tpm-enacttrust/evidence_handler.go delete mode 100644 scheme/tpm-enacttrust/evidence_handler_test.go delete mode 100644 scheme/tpm-enacttrust/extractor.go delete mode 100644 scheme/tpm-enacttrust/instanceattributes.go delete mode 100644 scheme/tpm-enacttrust/plugin/combined/Makefile delete mode 100644 scheme/tpm-enacttrust/plugin/combined/main.go delete mode 100644 scheme/tpm-enacttrust/plugin/endorsement-handler/Makefile delete mode 100644 scheme/tpm-enacttrust/plugin/evidence-handler/Makefile delete mode 100644 scheme/tpm-enacttrust/plugin/evidence-handler/main.go rename scheme/tpm-enacttrust/plugin/{endorsement-handler => }/main.go (62%) delete mode 100644 scheme/tpm-enacttrust/plugin/store-handler/Makefile delete mode 100644 scheme/tpm-enacttrust/plugin/store-handler/main.go delete mode 100644 scheme/tpm-enacttrust/store_handler.go delete mode 100644 scheme/tpm-enacttrust/store_handler_test.go delete mode 100644 scheme/tpm-enacttrust/swcompattributes.go delete mode 100755 scheme/tpm-enacttrust/test/corim/build-test-vectors.sh create mode 100755 scheme/tpm-enacttrust/test/corim/compile-endorsements.sh create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-class.cbor create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-instance.cbor create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-digests.cbor rename scheme/tpm-enacttrust/test/corim/{unsignedCorimMiniComidTpmEnactTrustAKMult.cbor => corim-enacttrust-bad-multiple-keys.cbor} (67%) create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-measurements.cbor create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-digest.cbor create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-instance.cbor create mode 100644 scheme/tpm-enacttrust/test/corim/corim-enacttrust-valid.cbor create mode 100644 scheme/tpm-enacttrust/test/corim/src/comid-bad-class.json rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustBadInst.json => comid-bad-instance.json} (100%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustMultDigest.json => comid-bad-multiple-digests.json} (100%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustAKMult.json => comid-bad-multiple-keys.json} (100%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustGoldenTwo.json => comid-bad-multiple-measurements.json} (100%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustNoDigest.json => comid-bad-no-digest.json} (100%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustNoInst.json => comid-bad-no-instance.json} (100%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustGoldenOne.json => comid-enacttrust-refval.json} (75%) rename scheme/tpm-enacttrust/test/corim/src/{ComidTpmEnactTrustAKOne.json => comid-enacttrust-ta.json} (70%) rename scheme/tpm-enacttrust/test/corim/src/{corimMini.json => corim-enacttrust.json} (50%) create mode 100644 scheme/tpm-enacttrust/test/corim/src/corims.yaml create mode 100755 scheme/tpm-enacttrust/test/corim/submit-enacttrust-endorsements.sh delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKBadInst.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustBadInst.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenOne.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor delete mode 100644 scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor rename scheme/tpm-enacttrust/test/{tokens => evidence}/Makefile (100%) rename scheme/tpm-enacttrust/test/{tokens => evidence}/basic.json (100%) rename scheme/tpm-enacttrust/test/{tokens => evidence}/basic.token (100%) create mode 100755 scheme/tpm-enacttrust/test/evidence/submit-enacattrust-evidence.sh delete mode 100644 scheme/tpm-enacttrust/test/refval.json delete mode 100644 scheme/tpm-enacttrust/test/trustanchor.json create mode 100644 scheme/tpm-enacttrust/test_vars.go delete mode 100644 scheme/tpm-enacttrust/test_vectors.go create mode 100755 scripts/generate-corims create mode 100755 scripts/generate-test-vector-embeds delete mode 100644 vts/appraisal/appraisal.go create mode 100644 vts/appraisal/context.go create mode 100644 vts/appraisal/evidence.go create mode 100644 vts/store/store.go diff --git a/.gitignore b/.gitignore index 41cac9e5..af3e0cec 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ __pycache__ __debug_bin* management/cmd/management-service/management-service coserv/cmd/coserv-service/coserv-service +__build* # Test binary, built with `go test -c` *.test diff --git a/.golangci.yml b/.golangci.yml index 70e08020..44d256ed 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,2 +1,21 @@ run: - go: '1.18' + go: "1.18" +linters: + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/Makefile b/Makefile index 78b3398b..a50dab54 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,6 @@ # Copyright 2021-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -# There will be one plugin built for each scheme. Removing this definition will -# cause a separate plugin to be built for each handler interface (endorsement, -# store, and verification), resulting in three plugins per scheme. -export COMBINED_PLUGINS = 1 - SHELL = /bin/bash SUBDIR += builtin @@ -53,6 +48,12 @@ IGNORE_COVERAGE += github.com/veraison/services/coserv/cmd/coserv-service IGNORE_COVERAGE += github.com/veraison/services/scheme/amd-kds-coserv IGNORE_COVERAGE += github.com/veraison/services/scheme/nvidia-coserv IGNORE_COVERAGE += github.com/veraison/services/scheme/arm-cca +IGNORE_COVERAGE += github.com/veraison/services/scheme/parsec-cca +IGNORE_COVERAGE += github.com/veraison/services/scheme/parsec-tpm +IGNORE_COVERAGE += github.com/veraison/services/scheme/psa-iot +IGNORE_COVERAGE += github.com/veraison/services/scheme/riot +IGNORE_COVERAGE += github.com/veraison/services/scheme/sevsnp +IGNORE_COVERAGE += github.com/veraison/services/scheme/tpm-enacttrust include mk/cover.mk diff --git a/auth/keycloak.go b/auth/keycloak.go index 5880d3d5..b48fa137 100644 --- a/auth/keycloak.go +++ b/auth/keycloak.go @@ -1,10 +1,10 @@ -// Copyright 2023-2024 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package auth import ( - "crypto/x509" "crypto/tls" + "crypto/x509" "errors" "flag" "fmt" @@ -20,11 +20,11 @@ import ( ) type keycloakCfg struct { - Backend string `mapstructure:"backend"` - Host string `mapstructure:"host"` - Port string `mapstructure:"port"` - Realm string `mapstructure:"realm"` - CACert string `mapstructure:"ca-cert"` + Backend string `mapstructure:"backend"` + Host string `mapstructure:"host"` + Port string `mapstructure:"port"` + Realm string `mapstructure:"realm"` + CACert string `mapstructure:"ca-cert"` } type KeycloakAuthorizer struct { @@ -43,9 +43,9 @@ func (o *KeycloakAuthorizer) Init(v *viper.Viper, logger *zap.SugaredLogger) err flag.Parse() cfg := keycloakCfg{ - Host: "localhost", - Port: "11111", - Realm: "veraison", + Host: "localhost", + Port: "11111", + Realm: "veraison", CACert: "[unset]", } diff --git a/builtin/builtin_loader.go b/builtin/builtin_loader.go index 4019fd9f..c5bac4e2 100644 --- a/builtin/builtin_loader.go +++ b/builtin/builtin_loader.go @@ -1,4 +1,4 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package builtin @@ -52,6 +52,19 @@ func (o *BuiltinLoader) GetRegisteredMediaTypes() []string { return mediaTypes } +func (o *BuiltinLoader) GetRegisteredMediaTypesByCategory(category string) []string { + var mediaTypes []string // nolint:prealloc + + for _, pluggable := range o.loadedByMediaType { + mts, ok := pluggable.GetSupportedMediaTypes()[category] + if ok { + mediaTypes = append(mediaTypes, mts...) + } + } + + return mediaTypes +} + func DiscoverBuiltin[I plugin.IPluggable]() error { return DiscoverBuiltinUsing[I](defaultBuiltinLoader) } @@ -71,15 +84,17 @@ func DiscoverBuiltinUsing[I plugin.IPluggable](loader *BuiltinLoader) error { loader.logger.Debugw("found plugin", "name", name) loader.loadedByName[name] = p - for _, mt := range p.GetSupportedMediaTypes() { - if existing, ok := loader.loadedByMediaType[mt]; ok { - loader.logger.Panicw("media type handled by two plugins", - "media-type", mt, - "plugin1", existing.GetName(), "plugin2", name) - } + for _, mts := range p.GetSupportedMediaTypes() { + for _, mt := range mts { + if existing, ok := loader.loadedByMediaType[mt]; ok { + loader.logger.Panicw("media type handled by two plugins", + "media-type", mt, + "plugin1", existing.GetName(), "plugin2", name) + } - loader.logger.Debugw("media type handled", "media-type", mt, "name", name) - loader.loadedByMediaType[mt] = p + loader.logger.Debugw("media type handled", "media-type", mt, "name", name) + loader.loadedByMediaType[mt] = p + } } } diff --git a/builtin/builtin_manager.go b/builtin/builtin_manager.go index a7f6d281..1f56ac28 100644 --- a/builtin/builtin_manager.go +++ b/builtin/builtin_manager.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package builtin @@ -73,8 +73,8 @@ func (o *BuiltinManager[I]) IsRegisteredMediaType(mediaType string) bool { func (o *BuiltinManager[I]) GetRegisteredMediaTypes() []string { var registeredMediatTypes []string - for mtName, mt := range o.loader.loadedByMediaType { - if _, ok := mt.(I); ok { + for mtName, pc := range o.loader.loadedByMediaType { + if _, ok := pc.(I); ok { registeredMediatTypes = append(registeredMediatTypes, mtName) } } @@ -82,6 +82,21 @@ func (o *BuiltinManager[I]) GetRegisteredMediaTypes() []string { return registeredMediatTypes } +func (o *BuiltinManager[I]) GetRegisteredMediaTypesByCategory(category string) []string { + var registeredMediatTypes []string + + for _, pc := range o.loader.loadedByName { + if pluggable, ok := pc.(I); ok { + mts, ok := pluggable.GetSupportedMediaTypes()[category] + if ok { + registeredMediatTypes = append(registeredMediatTypes, mts...) + } + } + } + + return registeredMediatTypes +} + func (o *BuiltinManager[I]) GetRegisteredAttestationSchemes() []string { return GetBuiltinLoadedAttestationSchemes[I](o.loader) } diff --git a/builtin/schemes.go b/builtin/schemes.go index 461ee8e6..9cad0e3a 100644 --- a/builtin/schemes.go +++ b/builtin/schemes.go @@ -1,38 +1,30 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package builtin import ( + "github.com/veraison/services/handler" "github.com/veraison/services/plugin" - scheme8 "github.com/veraison/services/scheme/amd-kds-coserv" + scheme9 "github.com/veraison/services/scheme/amd-kds-coserv" scheme3 "github.com/veraison/services/scheme/arm-cca" - scheme7 "github.com/veraison/services/scheme/nvidia-coserv" + scheme8 "github.com/veraison/services/scheme/nvidia-coserv" scheme1 "github.com/veraison/services/scheme/parsec-cca" scheme5 "github.com/veraison/services/scheme/parsec-tpm" scheme6 "github.com/veraison/services/scheme/psa-iot" scheme2 "github.com/veraison/services/scheme/riot" + scheme7 "github.com/veraison/services/scheme/sevsnp" scheme4 "github.com/veraison/services/scheme/tpm-enacttrust" ) var plugins = []plugin.IPluggable{ - &scheme1.EvidenceHandler{}, - &scheme1.EndorsementHandler{}, - &scheme1.StoreHandler{}, - &scheme2.EvidenceHandler{}, - &scheme2.StoreHandler{}, - &scheme3.EvidenceHandler{}, - &scheme3.EndorsementHandler{}, - &scheme3.StoreHandler{}, - &scheme4.EvidenceHandler{}, - &scheme4.EndorsementHandler{}, - &scheme4.StoreHandler{}, - &scheme5.EvidenceHandler{}, - &scheme5.EndorsementHandler{}, - &scheme5.StoreHandler{}, - &scheme6.EvidenceHandler{}, - &scheme6.EndorsementHandler{}, - &scheme6.StoreHandler{}, - &scheme7.CoservProxyHandler{}, + handler.MustNewSchemeImplementationWrapper(scheme1.Descriptor, scheme1.NewImplementation()), + handler.MustNewSchemeImplementationWrapper(scheme2.Descriptor, scheme2.NewImplementation()), + handler.MustNewSchemeImplementationWrapper(scheme3.Descriptor, scheme3.NewImplementation()), + handler.MustNewSchemeImplementationWrapper(scheme4.Descriptor, scheme4.NewImplementation()), + handler.MustNewSchemeImplementationWrapper(scheme5.Descriptor, scheme5.NewImplementation()), + handler.MustNewSchemeImplementationWrapper(scheme6.Descriptor, scheme6.NewImplementation()), + handler.MustNewSchemeImplementationWrapper(scheme7.Descriptor, scheme7.NewImplementation()), &scheme8.CoservProxyHandler{}, + &scheme9.CoservProxyHandler{}, } diff --git a/coserv/test-harness/amd.sh b/coserv/test-harness/amd.sh index ce10e8d4..1b9afc12 100755 --- a/coserv/test-harness/amd.sh +++ b/coserv/test-harness/amd.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 set -o pipefail set -eu diff --git a/coserv/test-harness/nvidia.sh b/coserv/test-harness/nvidia.sh index da5f122d..8be655ca 100755 --- a/coserv/test-harness/nvidia.sh +++ b/coserv/test-harness/nvidia.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 set -o pipefail set -eu diff --git a/coserv/test-harness/query.sh b/coserv/test-harness/query.sh index 523a8e5e..b02caf73 100755 --- a/coserv/test-harness/query.sh +++ b/coserv/test-harness/query.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 set -o pipefail set -eu diff --git a/deployments/aws/bin/veraison b/deployments/aws/bin/veraison index c078790e..1c16e9ab 100755 --- a/deployments/aws/bin/veraison +++ b/deployments/aws/bin/veraison @@ -1,4 +1,6 @@ #!/usr/bin/env python +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 # pyright: reportOptionalMemberAccess=false # pyright: reportOptionalSubscript=false # pyright: reportOperatorIssue=false @@ -18,6 +20,7 @@ import socket import stat import string import sys +import tempfile import time from asyncio.subprocess import Process, PIPE from collections import defaultdict @@ -1503,13 +1506,28 @@ class CreateSentinelImageCommand(BaseCommand): '../misc/sentinel-commands', )), ) + parser.add_argument( + '-P', '--package', + default='github.com/veraison/corim-store/cmd/corim-store', + ) + parser.add_argument( '-R', '--rev', default='9e4ba68b') parser.add_argument('-T', '--instance-type') def run(self, args): - command_create_image(self, args, 'sentinel', - { - 'command_dispatcher_path': args.dispatcher, - }) + dir = tempfile.mkdtemp() + try: + run_in_shell(f"GOBIN={dir} go install {args.package}@{args.rev}", args.verbose) + path = os.path.join(dir, 'corim-store') + self.logger.debug(f'installed corim-store: {path}') + + command_create_image(self, args, 'sentinel', + { + 'corim_store_exe_path': path, + 'command_dispatcher_path': args.dispatcher, + }) + finally: + self.logger.debug(f'deleting: {dir}') + shutil.rmtree(dir) class DeleteImageCommand(BaseCommand): diff --git a/deployments/aws/deployment.sh b/deployments/aws/deployment.sh index bceb628e..1eb407c0 100755 --- a/deployments/aws/deployment.sh +++ b/deployments/aws/deployment.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 set -ueo pipefail _error='\e[0;31mERROR\e[0m' diff --git a/deployments/aws/misc/sentinel-commands b/deployments/aws/misc/sentinel-commands index 2e3caa6c..58814932 100644 --- a/deployments/aws/misc/sentinel-commands +++ b/deployments/aws/misc/sentinel-commands @@ -1,12 +1,17 @@ #!/opt/veraison/venv/bin/python import argparse +import asyncio import inspect import logging import json +import os +import pathlib import shutil import sys +from asyncio.subprocess import Process, PIPE import psycopg2 +import yaml from psycopg2.errors import DuplicateDatabase @@ -22,27 +27,15 @@ COLOR_RESET = '\x1b[0m' PGSQL_SETUP = ''' -CREATE TABLE IF NOT EXISTS endorsements ( - kv_key TEXT NOT NULL, - kv_val TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS trust_anchors ( - kv_key TEXT NOT NULL, - kv_val TEXT NOT NULL -); CREATE TABLE IF NOT EXISTS policies ( kv_key TEXT NOT NULL, kv_val TEXT NOT NULL ); -CREATE INDEX ON endorsements(kv_key); -CREATE INDEX ON trust_anchors(kv_key); CREATE INDEX ON policies(kv_key); ''' CLEAR_STORES = ''' -DELETE FROM endorsements; -DELETE FROM trust_anchors; DELETE FROM policies; ''' @@ -156,7 +149,27 @@ class SetupRdsCommand(BaseCommand): finally: con.close() - self.logger.debug('updating cache with DB connection settings...') + self.logger.info('configuring corim-store client...') + corim_store_settings = { + 'dbms': 'pg', + 'dsn': f'postgres://veraison:{args.password}@{args.host}:{args.port}/veraison?sslmode=disable', + 'trace-sql': False, + } + self.logger.debug(f'corim-store settings: {corim_store_settings}') + + config_dir = os.path.expanduser('~/.config') + pathlib.Path(config_dir).mkdir(parents=True, exist_ok=True) + + config_file = os.path.join(config_dir, 'corim-store.yaml') + self.logger.debug(f'writing {config_file}...') + with open(config_file, 'w') as wfh: + yaml.dump(corim_store_settings, wfh) + + self.logger.info('initializing corim-store...') + exit_code, _, stderr = run_in_shell('corim-store db init', args.verbose) + if exit_code: + raise RuntimeError(stderr) + self.logger.info('done.') @@ -174,26 +187,15 @@ class CheckStoresCommand(BaseCommand): def run(self, args): con_line = (f'host={args.host} port={args.port} dbname=veraison ' f'user=veraison password={args.password}') - self.logger.debug(f'RDS connection settings: {con_line}') - with psycopg2.connect(con_line) as con: - with con.cursor() as cur: - print(f'{COLOR_GREEN}TRUST ANCHORS:\n--------------{COLOR_RESET}') - cur.execute('SELECT * FROM trust_anchors') - for key, value in cur.fetchall(): - print(key) - parsed = json.loads(value) - print(json.dumps(parsed, indent=4, sort_keys=True)) - print() - print(f'{COLOR_GREEN}ENDORSEMENTS:\n-------------{COLOR_RESET}') - cur.execute('SELECT * FROM endorsements') - for key, value in cur.fetchall(): - print(key) - parsed = json.loads(value) - print(json.dumps(parsed, indent=4, sort_keys=True)) - print() + exit_code, stdout, stderr = run_in_shell('corim-store list triples', args.verbose) + if exit_code: + raise RuntimeError(stderr) + print(stdout) + with psycopg2.connect(con_line) as con: + with con.cursor() as cur: print(f'{COLOR_GREEN}POLICIES:\n---------{COLOR_RESET}') cur.execute('SELECT * FROM policies') for key, value in cur.fetchall(): @@ -206,18 +208,20 @@ class ClearStoresCommand(BaseCommand): name = 'clear-stores' desc = 'clear the contents of deployment\'s sqlite3 stores' - def update_arguments(self, parser): parser.add_argument('host') parser.add_argument('port', type=int) parser.add_argument('password') - def run(self, args): con_line = (f'host={args.host} port={args.port} dbname=veraison ' f'user=veraison password={args.password}') - self.logger.debug(f'RDS connection settings: {con_line}') + + exit_code, _, stderr = run_in_shell('corim-store db clear', args.verbose) + if exit_code: + raise RuntimeError(stderr) + with psycopg2.connect(con_line) as con: with con.cursor() as cur: self.logger.info('clearing stores...') @@ -230,6 +234,44 @@ class ClearStoresCommand(BaseCommand): self.logger.info('done.') +def run_in_shell(cmd, should_log): + logger = logging.getLogger('shell') + if should_log: + logger.setLevel(logging.DEBUG) + + loop = asyncio.new_event_loop() + try: + return loop.run_until_complete(_run_in_shell_teed(cmd, logger)) + finally: + loop.close() + + +async def _run_in_shell_teed(cmd, logger): + process: Process = await asyncio.create_subprocess_shell( + cmd, stdout=PIPE, stderr=PIPE, cwd=os.getcwd()) + + stdout_buf, stderr_buf = [], [] + tasks = { + asyncio.Task(process.stdout.readline()): (process.stdout, stdout_buf), # pyright: ignore[reportOptionalMemberAccess] + asyncio.Task(process.stderr.readline()): (process.stderr, stderr_buf), # pyright: ignore[reportOptionalMemberAccess] + } + + while tasks: + done, _ = await asyncio.wait( + tasks, return_when=asyncio.FIRST_COMPLETED) # pyright: ignore[reportCallIssue] + for future in done: + stream, buf = tasks.pop(future) + line = future.result() + if line: + line = line.decode() + buf.append(line) + logger.debug(line.rstrip('\n')) + tasks[asyncio.Task(stream.readline())] = stream, buf # pyright: ignore[reportOptionalMemberAccess] + + rc = await process.wait() + return rc, ''.join(stdout_buf), ''.join(stderr_buf) + + if __name__ == '__main__': handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) diff --git a/deployments/aws/templates/image-sentinel.pkr.hcl b/deployments/aws/templates/image-sentinel.pkr.hcl index b8e27758..67759c71 100644 --- a/deployments/aws/templates/image-sentinel.pkr.hcl +++ b/deployments/aws/templates/image-sentinel.pkr.hcl @@ -37,6 +37,10 @@ variable "command_dispatcher_path" { type = string } +variable "corim_store_exe_path" { + type = string +} + source "amazon-ebs" "ubuntu" { ami_name = "${var.ami_name}" instance_type = "${var.instance_type}" @@ -76,6 +80,11 @@ build { destination = "veraison-dispatcher" } + provisioner "file" { + source = "${var.corim_store_exe_path}" + destination = "corim-store" + } + provisioner "shell" { inline = [ "sudo apt-get update", @@ -87,9 +96,12 @@ build { "sudo mv veraison-dispatcher /opt/veraison/bin/veraison", "sudo chmod +x /opt/veraison/bin/veraison", "sudo ln -s /opt/veraison/bin/veraison /usr/bin/veraison", + "sudo mv corim-store /opt/veraison/bin/corim-store" + "sudo chmod +x /opt/veraison/bin/corim-store" + "sudo ln -s /opt/veraison/bin/corim-store /usr/bin/corim-store", "sudo python3 -mvenv /opt/veraison/venv", - "sudo /opt/veraison/venv/bin/pip install psycopg2 pyxdg", + "sudo /opt/veraison/venv/bin/pip install psycopg2 pyxdg pyyaml", "sudo NEEDRESTART_MODE=a apt-get remove --yes gcc", ] diff --git a/deployments/debian/debian/postinst b/deployments/debian/debian/postinst index fdaa232a..8c6d948e 100644 --- a/deployments/debian/debian/postinst +++ b/deployments/debian/debian/postinst @@ -1,4 +1,6 @@ #!/bin/sh +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 if [ "$1" = "configure" ]; then [ -z "$VERAISON_USER" ] && VERAISON_USER=veraison diff --git a/deployments/debian/debian/prerm b/deployments/debian/debian/prerm index bd5100c3..53948965 100644 --- a/deployments/debian/debian/prerm +++ b/deployments/debian/debian/prerm @@ -1,4 +1,6 @@ #!/bin/sh +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 if [ "$1" = "remove" ]; then [ -z "$VERAISON_USER" ] && VERAISON_USER=veraison diff --git a/deployments/debian/deployment.sh b/deployments/debian/deployment.sh index e3f38dbb..b9aa4d6f 100755 --- a/deployments/debian/deployment.sh +++ b/deployments/debian/deployment.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 set -eo pipefail _error='\e[0;31mERROR\e[0m' @@ -7,7 +9,6 @@ _deb_src=${_this_dir}/debian _repo_root=$(realpath "${_this_dir}/../..") _version=$("${_repo_root}/scripts/get-veraison-version") - function bootstrap() { "${_repo_root}/deployments/native/deployment.sh" bootstrap diff --git a/deployments/docker/src/builder-dispatcher b/deployments/docker/src/builder-dispatcher index e7c71b49..4fefb73d 100755 --- a/deployments/docker/src/builder-dispatcher +++ b/deployments/docker/src/builder-dispatcher @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2024 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 # shellcheck disable=SC2155,SC2086 # This script is the entry point for the builder docker container. @@ -46,6 +46,7 @@ function deploy() { cp $gobin/evcli $DEPLOY_DIR/utils/ cp $gobin/cocli $DEPLOY_DIR/utils/ cp $gobin/pocli $DEPLOY_DIR/utils/ + cp $gobin/corim-store $DEPLOY_DIR/utils/ echo "creating config" set -a @@ -56,12 +57,12 @@ function deploy() { cat $BUILD_DIR/deployments/docker/src/cocli-config.yaml.template | envsubst > $DEPLOY_DIR/utils/cocli-config.yaml cat $BUILD_DIR/deployments/docker/src/evcli-config.yaml.template | envsubst > $DEPLOY_DIR/utils/evcli-config.yaml cat $BUILD_DIR/deployments/docker/src/pocli-config.yaml.template | envsubst > $DEPLOY_DIR/utils/pocli-config.yaml + cat $BUILD_DIR/deployments/docker/src/corim-store-config.yaml.template | envsubst > $DEPLOY_DIR/utils/corim-store-config.yaml echo "initializing stores" - for t in en ta po; do - echo "CREATE TABLE IF NOT EXISTS kvstore ( kv_key text NOT NULL, kv_val text NOT NULL );" | \ - sqlite3 $DEPLOY_DIR/stores/$t-store.sql - done + echo "CREATE TABLE IF NOT EXISTS kvstore ( kv_key text NOT NULL, kv_val text NOT NULL );" | \ + sqlite3 $DEPLOY_DIR/stores/po-store.sql + $DEPLOY_DIR/utils/corim-store --dsn file://$DEPLOY_DIR/stores/store.sql db init } function clean() { diff --git a/deployments/docker/src/builder.docker b/deployments/docker/src/builder.docker index 0d7038de..e59404e6 100644 --- a/deployments/docker/src/builder.docker +++ b/deployments/docker/src/builder.docker @@ -63,7 +63,8 @@ RUN go mod download &&\ go install github.com/veraison/cocli@v1.0.0-alpha0 &&\ go install github.com/veraison/evcli/v2@1685bf5 &&\ go install github.com/veraison/pocli@v0.2.0 &&\ - go install github.com/go-delve/delve/cmd/dlv@v1.23.0 + go install github.com/go-delve/delve/cmd/dlv@v1.24.0 &&\ + go install github.com/veraison/corim-store/cmd/corim-store@9e4ba68b ADD --chown=builder:builder builder-dispatcher . ADD --chown=builder:builder builder-bashrc /home/builder/.bashrc diff --git a/deployments/docker/src/config.yaml.template b/deployments/docker/src/config.yaml.template index 4ee9d2c4..faa34f37 100644 --- a/deployments/docker/src/config.yaml.template +++ b/deployments/docker/src/config.yaml.template @@ -32,18 +32,9 @@ plugin: backend: go-plugin go-plugin: dir: ./plugins/ -ta-store: - backend: sql - sql: - max_connections: 10 - driver: sqlite3 - datasource: stores/vts/ta-store.sql -en-store: - backend: sql - sql: - max_connections: 10 - driver: sqlite3 - datasource: stores/vts/en-store.sql +store: + dbms: sqlite + dsn: stores/vts/store.sql po-store: backend: sql sql: diff --git a/deployments/docker/src/corim-store-config.yaml.template b/deployments/docker/src/corim-store-config.yaml.template new file mode 100644 index 00000000..2a39f0fb --- /dev/null +++ b/deployments/docker/src/corim-store-config.yaml.template @@ -0,0 +1,2 @@ +dbms: sqlite +dsn: file:///opt/veraison/stores/vts/store.sql diff --git a/deployments/docker/src/manager-dispatcher b/deployments/docker/src/manager-dispatcher index 218ad9f0..3e116034 100755 --- a/deployments/docker/src/manager-dispatcher +++ b/deployments/docker/src/manager-dispatcher @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2023-2024 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 # This script is the entry point for the builder docker container. shopt -s nullglob @@ -13,23 +13,21 @@ _host_root=/opt/veraison/hostroot function stores() { local query=${1:-.} - echo "TRUST ANCHORS:" - echo "--------------" - sqlite3 $_stores_dir/ta-store.sql 'select distinct kv_val from kvstore' | jq "$query" - + echo "ENDORSEMENTS & TRUST ANCHORS:" + echo "-----------------------------" + $_utils_dir/corim-store list triples echo "" - echo "ENDORSEMENTS:" - echo "-------------" - sqlite3 $_stores_dir/en-store.sql 'select distinct kv_val from kvstore' | jq "$query" + echo "POLICIES:" + echo "---------" + sqlite3 $_stores_dir/po-store.sql 'select distinct kv_val from kvstore' | jq "$query" echo "" } function clear_stores() { - sqlite3 $_stores_dir/en-store.sql 'delete from kvstore' sqlite3 $_stores_dir/po-store.sql 'delete from kvstore' - sqlite3 $_stores_dir/ta-store.sql 'delete from kvstore' + $_utils_dir/corim-store db clear } function logs() { @@ -69,6 +67,13 @@ function pocli() { /bin/bash -c "$cmd" } +function corim_store() { + local -a args + for arg in "$@"; do args+=("'$arg'"); done + local cmd="$_utils_dir/corim-store ${args[@]}" + /bin/bash -c "$cmd" +} + function _check_is_mount_point() { local -a expected=$1 local -r mounts=$(df | tail -n +2 | tr -s ' ' | cut -d' ' -f6) diff --git a/deployments/docker/src/manager.docker b/deployments/docker/src/manager.docker index c8e4fc49..5cacde51 100644 --- a/deployments/docker/src/manager.docker +++ b/deployments/docker/src/manager.docker @@ -39,11 +39,12 @@ WORKDIR /opt/veraison RUN mkdir -p /home/manager/.config/pocli && \ mkdir -p /home/manager/.config/cocli -ADD --chown=manager:nogroup utils/evcli utils/cocli utils/pocli ./utils/ +ADD --chown=manager:nogroup utils/evcli utils/cocli utils/pocli utils/corim-store ./utils/ ADD --chown=manager:nogroup manager-dispatcher ./ ADD --chown=manager:nogroup utils/cocli-config.yaml /home/manager/.config/cocli/config.yaml ADD --chown=manager:nogroup utils/evcli-config.yaml /home/manager/.config/evcli/config.yaml ADD --chown=manager:nogroup utils/pocli-config.yaml /home/manager/.config/pocli/config.yaml +ADD --chown=manager:nogroup utils/corim-store-config.yaml /home/manager/.config/corim-store.yaml ENTRYPOINT ["/opt/veraison/manager-dispatcher"] CMD ["help"] diff --git a/deployments/docker/veraison b/deployments/docker/veraison index 6a0953e7..e8a2b905 100755 --- a/deployments/docker/veraison +++ b/deployments/docker/veraison @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2023-2024 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 set -eo pipefail @@ -272,6 +272,25 @@ function kill_tmux_session() { fi } +function shell() { + local what="$1" + + local container_id + case "$what" in + vts | vts-service) container_id="vts-service" ;; + provisioning | provisioning-service) container_id="provisioning-service" ;; + verification | verification-service) container_id="verification-service" ;; + management | management-service) container_id="management-service" ;; + keycloak | keycloak-service) container_id="keycloak-service" ;; + *) + echo -e "$_error: unknown service: $what" + exit 1 + ;; + esac + + docker exec -it "$container_id" bash +} + function cocli() { local -a args for arg in "$@"; do args+=("$arg"); done @@ -296,6 +315,14 @@ function pocli() { manager pocli "${translated_args[@]}" } +function corim_store() { + local -a args + for arg in "$@"; do args+=("$arg"); done + # Note: calling _translated_host_paths sets translated_args + _translate_host_paths "${args[@]}" + manager corim-store "${translated_args[@]}" +} + function help() { set +e read -r -d '' usage <<-EOF @@ -365,6 +392,10 @@ function help() { Kill the tmux session created with the "tmux" command (see above). Note: this does NOT stop the services. + shell SERVICE + + Start a shell inside the container running the specified service. + EOF echo "$usage" set -e @@ -509,9 +540,11 @@ case $command in start-tmux) create_tmux_session "$2";; tmux | attach-tmux) attach_tmux_session "$2";; stop-tmux | kill-tmux) kill_tmux_session "$2";; + shell) shell "$2";; cocli) shift; cocli "$@";; evcli) shift; evcli "$@";; pocli) shift; pocli "$@";; + corim-store) shift; corim_store "$@";; debug) manager_debug "$@";; *) echo -e "$_error: unexpected command: \"$command\" (use -h for help)";; esac diff --git a/deployments/native/README.md b/deployments/native/README.md index 46d88088..e1df3f8f 100644 --- a/deployments/native/README.md +++ b/deployments/native/README.md @@ -20,6 +20,13 @@ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 go install github.com/mitchellh/protoc-gen-go-json@latest ``` +`corim-store` executable is used to initialized the endorsements store. This +can also be installed via Go: + +```bash +go install github.com/veraison/corim-store/cmd/corim-store@latest +``` + You will need GNU `make` (at least version 3.81) to drive the build process. The deployment script is written for `bash` shell, and relies on `envsubst` diff --git a/deployments/native/bin/veraison b/deployments/native/bin/veraison index dd5d0bdb..8017db15 100755 --- a/deployments/native/bin/veraison +++ b/deployments/native/bin/veraison @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2025 Contributors to the Veraison project. +# Copyright 2025-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 # shellcheck disable=SC2155,SC2086 set -e @@ -30,13 +30,14 @@ _launchd_ns="com.veraison-project" function init_sqlite_stores() { _check_installed sqlite3 + _check_installed corim-store local stores_dir=${1:-${_stores_dir}} - for t in en ta po; do - echo "CREATE TABLE IF NOT EXISTS kvstore ( kv_key text NOT NULL, kv_val text NOT NULL );" | \ - $_sqlite "${stores_dir}/${t}-store.sql" - done + echo "CREATE TABLE IF NOT EXISTS kvstore ( kv_key text NOT NULL, kv_val text NOT NULL );" | \ + $_sqlite "${stores_dir}/po-store.sql" + + corim_store db init } function generate_signing_key() { @@ -247,15 +248,9 @@ function show_stores() { local query=${1:-.} - echo "TRUST ANCHORS:" - echo "--------------" - $_sqlite "${_stores_dir}/ta-store.sql" 'SELECT DISTINCT kv_val FROM kvstore' | jq "$query" - - echo "" - - echo "ENDORSEMENTS:" - echo "-------------" - $_sqlite "${_stores_dir}/en-store.sql" 'SELECT DISTINCT kv_val FROM kvstore' | jq "$query" + echo "ENDORSEMENTS & TRUST ANCHORS:" + echo "-----------------------------" + corim_store list triples echo "" @@ -269,9 +264,9 @@ function show_stores() { function clear_stores() { _check_installed sqlite3 - $_sqlite "${_stores_dir}/en-store.sql" 'DELETE FROM kvstore' $_sqlite "${_stores_dir}/po-store.sql" 'DELETE FROM kvstore' - $_sqlite "${_stores_dir}/ta-store.sql" 'DELETE FROM kvstore' + corim_store db clear + } function enable_launchd_services() { @@ -496,6 +491,15 @@ function pocli() { ${_bin_dir}/pocli --config ${_config_dir}/pocli/config.yaml "$@" } +function corim_store() { + if [[ ! -f ${_bin_dir}/corim-store ]]; then + echo -e "$_error: corim-store not in deployment." + exit 1 + fi + + ${_bin_dir}/corim-store --config ${_config_dir}/corim-store/config.yaml "$@" +} + function help() { set +e read -r -d '' usage <<-EOF @@ -1002,6 +1006,9 @@ case $command in pocli) pocli "$@" ;; + corim-store) + corim_store "$@" + ;; *) echo -e "$_error: unexpected command: \"$command\" (use -h for help)" ;; diff --git a/deployments/native/bootstrap/arch.sh b/deployments/native/bootstrap/arch.sh index f9a4d486..bc193d67 100755 --- a/deployments/native/bootstrap/arch.sh +++ b/deployments/native/bootstrap/arch.sh @@ -1,9 +1,10 @@ #!/bin/sh -# Copyright 2024-2025 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 sudo pacman -Syy bash findutils grep sed openssl protobuf go make gettext sqlite3 jose jq go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 go install github.com/mitchellh/protoc-gen-go-json@latest +go install github.com/veraison/corim-store/cmd/corim-store@latest diff --git a/deployments/native/bootstrap/macosx-brew.sh b/deployments/native/bootstrap/macosx-brew.sh index 034be900..ef74a691 100755 --- a/deployments/native/bootstrap/macosx-brew.sh +++ b/deployments/native/bootstrap/macosx-brew.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright 2024-2025 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 set -eux @@ -11,3 +11,4 @@ brew link --force gettext go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 go install github.com/mitchellh/protoc-gen-go-json@latest +go install github.com/veraison/corim-store/cmd/corim-store@latest diff --git a/deployments/native/bootstrap/oraclelinux.sh b/deployments/native/bootstrap/oraclelinux.sh index 47a337f5..539a49ab 100755 --- a/deployments/native/bootstrap/oraclelinux.sh +++ b/deployments/native/bootstrap/oraclelinux.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright 2024-2025 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 sudo dnf install -y --enablerepo=ol9_codeready_builder git protobuf protobuf-devel gettext sqlite openssl jq jose golang @@ -7,4 +7,4 @@ sudo dnf install -y --enablerepo=ol9_codeready_builder git protobuf protobuf-dev go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 go install github.com/mitchellh/protoc-gen-go-json@latest - +go install github.com/veraison/corim-store/cmd/corim-store@latest diff --git a/deployments/native/bootstrap/ubuntu.sh b/deployments/native/bootstrap/ubuntu.sh index b648e047..07375ae7 100755 --- a/deployments/native/bootstrap/ubuntu.sh +++ b/deployments/native/bootstrap/ubuntu.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright 2024-2025 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 arch=$(dpkg --print-architecture) @@ -14,4 +14,4 @@ sudo ln -s /usr/lib/go-${go_ver}/bin/gofmt /usr/local/bin/gofmt go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 go install github.com/mitchellh/protoc-gen-go-json@latest - +go install github.com/veraison/corim-store/cmd/corim-store@latest diff --git a/deployments/native/config/corim-store.yaml.template b/deployments/native/config/corim-store.yaml.template new file mode 100644 index 00000000..77bdb046 --- /dev/null +++ b/deployments/native/config/corim-store.yaml.template @@ -0,0 +1,2 @@ +dbms: sqlite +dsn: file://${VERAISON_STORES_DIR}/store.sql diff --git a/deployments/native/config/services.yaml.template b/deployments/native/config/services.yaml.template index 84acbfcb..8c4b2a00 100644 --- a/deployments/native/config/services.yaml.template +++ b/deployments/native/config/services.yaml.template @@ -32,10 +32,10 @@ plugin: go-plugin: dir: ${VERAISON_PLUGINS_DIR}/ ############################################################################## -# The {ta,en,po}-store entries below configure the key-value stores for trust -# anchors, and policies. They are configured to use the "sql" backend with -# "sqlite3" driver by default. sqlite3 databases for these stores would have -# been configured as part of the deployment. +# The store entries below configure the stores for endorsements, trust +# anchors, and policies. They are configured to use sqlite3 by default. sqlite3 +# databases for these stores would have been configured as part of the +# deployment. # Following each driver config are commented out configs for alternate drivers. # In order to use these drivers, the corresponding DBMS must first be set up # and initialized for Veraison use. If that is the case, you can comment out @@ -45,36 +45,17 @@ plugin: # on localhost on its default port, the user is "veraison" with password # "password", and the relevant database is "veraison". ############################################################################## -ta-store: - backend: sql - sql: - max_connections: 10 - - driver: sqlite3 - datasource: ${VERAISON_STORES_DIR}/ta-store.sql - - #driver: pgx - #datasource: postgres://veraison:password@localhost:5432/veraison - #tablename: trust_anchors - - #driver: mysql - #datasource: veraison:password@tcp(localhost:3306)/veraison - #tablename: trust_anchors -en-store: - backend: sql - sql: - max_connections: 10 - - driver: sqlite3 - datasource: ${VERAISON_STORES_DIR}/en-store.sql +store: + trace-sql: false - #driver: pgx - #datasource: postgres://veraison:password@localhost:5432/veraison - #tablename: endorsements + dbms: sqlite3 + dsn: ${VERAISON_STORES_DIR}/store.sql - #driver: mysql - #datasource: veraison:password@tcp(localhost:3306)/veraison - #tablename: endorsements + #dbms: pgx + #dsn: postgres://veraison:password@localhost:5432/veraison + + #dbms: mysql + #dsn: veraison:password@tcp(localhost:3306)/veraison po-store: backend: sql sql: diff --git a/deployments/native/deployment.sh b/deployments/native/deployment.sh index a6dfeb12..85de517c 100755 --- a/deployments/native/deployment.sh +++ b/deployments/native/deployment.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2024-2025 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 # shellcheck disable=SC2155,SC2086 @@ -223,13 +223,17 @@ function init_signing_key() { } function init_sqlite_stores() { - ${DEPLOYMENT_BIN_DIR}/veraison init-sqlite-stores ${DEPLOYMENT_STORES_DIR} + ${DEPLOYMENT_BIN_DIR}/corim-store --dsn ${DEPLOYMENT_STORES_DIR}/store.sql db init + + echo "CREATE TABLE IF NOT EXISTS kvstore ( kv_key text NOT NULL, kv_val text NOT NULL );" | \ + sqlite3 "${DEPLOYMENT_STORES_DIR}/po-store.sql" } function init_clients() { - _init_client evcli github.com/veraison/evcli/v2@0d3a093 + _init_client evcli github.com/veraison/evcli/v2@v2.1.0 _init_client cocli github.com/veraison/cocli@8ebd64c1 _init_client pocli github.com/veraison/pocli@2fa24ea3 + _init_client corim-store github.com/veraison/corim-store/cmd/corim-store@9e4ba68b } function quick_init_all(){ @@ -247,8 +251,8 @@ function quick_init_all(){ create_deployment $bins_mode init_certs $cnk_mode $template $root_cert_path $root_cert_key_path init_signing_key $cnk_mode - init_sqlite_stores init_clients + init_sqlite_stores } function setup_keycloak() { @@ -484,7 +488,9 @@ function _gen_certs() { _f="-f" fi - ${DEPLOYMENT_BIN_DIR}/veraison $_f gen-service-certs $template \ + export VERAISON_CERTS_DIR=${DEPLOYMENT_CERTS_DIR} + export VERAISON_SIGNING_DIR=${DEPLOYMENT_SIGNING_DIR} + ${SRC_BIN_DIR}/veraison $_f gen-service-certs $template \ $root_cert_path $root_key_path } @@ -498,7 +504,9 @@ function _gen_signing_key() { _f="-f" fi - ${DEPLOYMENT_BIN_DIR}/veraison $_f gen-signing-key + export VERAISON_CERTS_DIR=${DEPLOYMENT_CERTS_DIR} + export VERAISON_SIGNING_DIR=${DEPLOYMENT_SIGNING_DIR} + ${SRC_BIN_DIR}/veraison $_f gen-signing-key } function _deploy_services_config() { diff --git a/deployments/native/env/env.bash b/deployments/native/env/env.bash index ed8bcba6..0c74defe 100644 --- a/deployments/native/env/env.bash +++ b/deployments/native/env/env.bash @@ -5,3 +5,4 @@ alias veraison="${VERAISON_BIN_DIR}/veraison" alias cocli="${VERAISON_BIN_DIR}/veraison cocli" alias evcli="${VERAISON_BIN_DIR}/veraison evcli" alias pocli="${VERAISON_BIN_DIR}/veraison pocli" +alias corim-store="${VERAISON_BIN_DIR}/veraison corim-store" diff --git a/deployments/native/env/env.zsh b/deployments/native/env/env.zsh index 42bd3d51..c4219d18 100644 --- a/deployments/native/env/env.zsh +++ b/deployments/native/env/env.zsh @@ -4,3 +4,4 @@ alias veraison="${VERAISON_BIN_DIR}/veraison" alias cocli="${VERAISON_BIN_DIR}/veraison cocli" alias evcli="${VERAISON_BIN_DIR}/veraison evcli" alias pocli="${VERAISON_BIN_DIR}/veraison pocli" +alias corim-store="${VERAISON_BIN_DIR}/veraison corim-store" diff --git a/deployments/rpm/deployment.sh b/deployments/rpm/deployment.sh index b07136e5..4c557e0b 100755 --- a/deployments/rpm/deployment.sh +++ b/deployments/rpm/deployment.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 set -eo pipefail _error='\e[0;31mERROR\e[0m' diff --git a/end-to-end/end-to-end-docker b/end-to-end/end-to-end-docker index 706b9c14..4e7eeebd 100755 --- a/end-to-end/end-to-end-docker +++ b/end-to-end/end-to-end-docker @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2022-2024 Contributors to the Veraison project. +# Copyright 2022-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 SCHEME=${SCHEME:-psa} @@ -13,11 +13,11 @@ function provision() { case $SCHEME in psa) local corim_file=$THIS_DIR/input/psa-endorsements.cbor - local media_type="application/corim-unsigned+cbor; profile=\"http://arm.com/psa/iot/1\"" + local media_type="application/rim+cbor; profile=\"http://arm.com/psa/iot/1\"" ;; cca) local corim_file=$THIS_DIR/input/cca-endorsements.cbor - local media_type="application/corim-unsigned+cbor; profile=\"http://arm.com/cca/ssd/1\"" + local media_type="application/rim+cbor; profile=\"http://arm.com/cca/ssd/1\"" ;; *) echo "ERROR: bad SCHEME: $SCHEME" diff --git a/end-to-end/end-to-end-native b/end-to-end/end-to-end-native index 2555b7eb..0cb3f85a 100755 --- a/end-to-end/end-to-end-native +++ b/end-to-end/end-to-end-native @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2024 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 if [[ $VERAISON_ROOT == "" ]]; then echo "ERROR: VERAISON_ROOT must be set." @@ -32,11 +32,11 @@ function provision() { case $SCHEME in psa) local corim_file=$THIS_DIR/input/psa-endorsements.cbor - local media_type="application/corim-unsigned+cbor; profile=\"http://arm.com/psa/iot/1\"" + local media_type="application/rim+cbor; profile=\"http://arm.com/psa/iot/1\"" ;; cca) local corim_file=$THIS_DIR/input/cca-endorsements.cbor - local media_type="application/corim-unsigned+cbor; profile=\"http://arm.com/cca/ssd/1\"" + local media_type="application/rim+cbor; profile=\"http://arm.com/cca/ssd/1\"" ;; *) echo "ERROR: bad SCHEME: $SCHEME" diff --git a/end-to-end/input/cca-claims-without-realm-challenge.json b/end-to-end/input/cca-claims-without-realm-challenge.json index 3869b652..49687a8c 100644 --- a/end-to-end/input/cca-claims-without-realm-challenge.json +++ b/end-to-end/input/cca-claims-without-realm-challenge.json @@ -1,5 +1,6 @@ { "cca-platform-token": { + "cca-platform-challenge": "5QHHS9edCpI1N1heeR7DUBI+gaqXUB34EkQCITSCxVM=", "cca-platform-profile": "http://arm.com/CCA-SSD/1.0.0", "cca-platform-implementation-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "cca-platform-instance-id": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC", @@ -45,6 +46,6 @@ ], "cca-realm-hash-algo-id": "sha-256", "cca-realm-public-key": "pAECIAIhWDCC+9EyqbXDloefuxU0DZBQl45Vx51SeaK6DpWFTzfiDNL2TztytXC713Pu4s52hCUiWDDt9UXtvon/r+Dpa71G4nDyB5bESLmNr0anZNJ0Qubm7YT4zsgX5uzGpx06PefWfs0=", - "cca-realm-public-key-hash-algo-id": "sha-256" + "cca-realm-public-key-hash-algo-id": "sha-512" } } diff --git a/end-to-end/input/cca-endorsements.cbor b/end-to-end/input/cca-endorsements.cbor index 55b2e8d367d10e68833801e8e1b8246d39245438..ddd383b3cdf0430b67e81080b498bfda3084b20e 100644 GIT binary patch delta 31 fcmcb@afL(dCgay-3;_%fz<6dEn8CPF%#H;BjL-)W delta 31 pcmV+)0O0@B2-FA`*#Y&Y08m_4==4U-LK~6E2+xz@Jp8d1J_P5i4tW3o diff --git a/end-to-end/input/cca-evidence.cbor b/end-to-end/input/cca-evidence.cbor index 9fd5679f1c8ee124cbf4c293e49c4a0ac67a3e98..048c65259c7c5f68b90370cf98b7d2503a5f898d 100644 GIT binary patch delta 278 zcmV+x0qOqn3XuyG*#VED8LY}#0+Z5&L!kjCpjiS(krX6GK+sV2_CZJHP#E0m*Te-l z?s%a2*gX5MyxXfo(g*bD?jn31uC_3{|`yyU!w|lW@XLT-Xo*4;T zSRj#M9kF}D0YI9*<0>7hpc1^MA>Y@kqw1&L%+#1anASY@KD`r zV5kJuz#YSVXcNU~o|vV$tsde*u3bP(3|$7lOTul-G&s2)2#3b0td5c$;=P396z;l1 w%Fi_%SbTi&pOWgcq7EzQ;zH8WLfaqUu~|vaoR1gzrS;6Iz;l(=kYZ$MEhi9kf&c&j diff --git a/end-to-end/input/cca-realm-endorsements.cbor b/end-to-end/input/cca-realm-endorsements.cbor index 27672320aace89ddd687d20d66f5e5f85d590357..6938cb14deaef2fc3282924e3d1d4e707ab25062 100644 GIT binary patch delta 44 tcmey%dWlu;Cgazo3;_%fz<6c}n8C={c$4v0BvaZ%xg^Gg8`lIf0RS0|45$DA delta 87 zcmV-d0I2`c1^opc*#Y&X08m_4==4U-LK~6E2+xz@Jp2KH*#Y`l0+Ep(Vl1Knq5#+> tP|Y6>RVMjH4Y}C&{o!$Vd;xP;Z*psFZ((F0Lu_efZge0_bY!uCQ3BRVCNls4 diff --git a/end-to-end/input/psa-endorsements.cbor b/end-to-end/input/psa-endorsements.cbor index db5fe6c787ed9918946f137dd9b08a4ebfeb91f4..8391de08b9ba428d80ffffadf812f5e0a2312598 100644 GIT binary patch delta 52 pcmX@Yc9Tu}Cgaz|3>7K{P@oHA#4F~`L delta 31 pcmV+)0O0@G2E+yy*#Y&V08m_4==4U-LK~6E2+xz@Jp8dME(7J<4r>4a diff --git a/end-to-end/input/psa-evidence.cbor b/end-to-end/input/psa-evidence.cbor index bbe738690c2f3385f82271834120ca99b5910253..6a0da0120b81d458deefc5f37bebd7a3f531f59d 100644 GIT binary patch delta 72 zcmV-O0Js051fm46;sHQdu1^3_(bv4{g{`7fm7XiuoysmxPCX=`i4;P%YUY-+0n_Mc e*@I}_v>ENTx5vg-omCx!BN4L? e6-g%EMC"}, nil + } + + return &ValidateCorimResponse{IsValid: true, Message: ""}, nil +} + +func (o *SchemeImplementationWrapper) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + return o.Impl.GetTrustAnchorIDs(evidence) +} + +func (o *SchemeImplementationWrapper) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + impl, ok := o.Impl.(interface { + GetReferenceValueIDs([]*comid.KeyTriple, map[string]any) ([]*comid.Environment, error) + }) + + if ok { + return impl.GetReferenceValueIDs(trustAnchors, claims) + } + + return nil, nil +} + +func (o *SchemeImplementationWrapper) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + if !o.Desc.EvidenceIsSupported(evidence) { + return nil, BadEvidence("wrong media type: expect %q, but found %q", + strings.Join(o.Desc.EvidenceMediaTypes, ", "), + evidence.MediaType, + ) + } + + return o.Impl.ExtractClaims(evidence, trustAnchors) +} + +func (o *SchemeImplementationWrapper) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + impl, ok := o.Impl.(interface { + ValidateEvidenceIntegrity(*appraisal.Evidence, []*comid.KeyTriple, []*comid.ValueTriple) error + }) + + if ok { + return impl.ValidateEvidenceIntegrity(evidence, trustAnchors, endorsements) + } + + return nil +} + +func (o *SchemeImplementationWrapper) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + return o.Impl.AppraiseClaims(claims, endorsements) +} + +type ValidateCorimResponse struct { + IsValid bool `json:"is-valid"` + Message string `json:"mesage"` +} + +func (o *ValidateCorimResponse) Error() error { + if o.Message == "" { + return nil + } + + return errors.New(o.Message) +} diff --git a/handler/store_rpc.go b/handler/store_rpc.go deleted file mode 100644 index 2e511594..00000000 --- a/handler/store_rpc.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import ( - "encoding/json" - "fmt" - "net/rpc" - - "github.com/veraison/services/plugin" - "github.com/veraison/services/proto" -) - -/* - Server-side RPC adapter around the Decoder plugin implementation - (plugin-side) -*/ - -var StoreHandlerRPC = &plugin.RPCChannel[IStoreHandler]{ - GetClient: getStoreClient, - GetServer: getStoreServer, -} - -func getStoreClient(c *rpc.Client) interface{} { - return &StoreRPCClient{client: c} -} - -func getStoreServer(i IStoreHandler) interface{} { - return &StoreRPCServer{Impl: i} -} - -type StoreRPCServer struct { - Impl IStoreHandler -} - -func (s *StoreRPCServer) GetName(args interface{}, resp *string) error { - *resp = s.Impl.GetName() - return nil -} - -func (s *StoreRPCServer) GetAttestationScheme(args interface{}, resp *string) error { - *resp = s.Impl.GetAttestationScheme() - return nil -} - -func (s *StoreRPCServer) GetSupportedMediaTypes(args interface{}, resp *[]string) error { - *resp = s.Impl.GetSupportedMediaTypes() - return nil -} - -type SynthKeysArgs struct { - TenantID string - EndorsementJSON []byte -} - -func (s *StoreRPCServer) SynthKeysFromRefValue(args SynthKeysArgs, resp *[]string) error { - var ( - err error - refVal Endorsement - ) - - err = json.Unmarshal(args.EndorsementJSON, &refVal) - if err != nil { - return fmt.Errorf("unmarshaling reference value: %w", err) - } - - *resp, err = s.Impl.SynthKeysFromRefValue(args.TenantID, &refVal) - - return err -} - -func (s *StoreRPCServer) SynthKeysFromTrustAnchor(args SynthKeysArgs, resp *[]string) error { - var ( - err error - ta Endorsement - ) - - err = json.Unmarshal(args.EndorsementJSON, &ta) - if err != nil { - return fmt.Errorf("unmarshaling trust anchor: %w", err) - } - - *resp, err = s.Impl.SynthKeysFromTrustAnchor(args.TenantID, &ta) - - return err -} - -func (s *StoreRPCServer) GetTrustAnchorIDs(data []byte, resp *[]string) error { - var ( - err error - token proto.AttestationToken - ) - - err = json.Unmarshal(data, &token) - if err != nil { - return fmt.Errorf("unmarshaling attestation token: %w", err) - } - - *resp, err = s.Impl.GetTrustAnchorIDs(&token) - - return err -} - -type GetRefValueIDsArgs struct { - TenantID string - TrustAnchors []string - Claims []byte -} - -func (s *StoreRPCServer) GetRefValueIDs(args GetRefValueIDsArgs, resp *[]string) error { - var claims map[string]interface{} - - err := json.Unmarshal(args.Claims, &claims) - if err != nil { - return fmt.Errorf("unmarshaling token: %w", err) - } - - *resp, err = s.Impl.GetRefValueIDs(args.TenantID, args.TrustAnchors, claims) - - return err -} - -type SynthCoservQueryKeysArgs struct { - TenantID string - Query string -} - -func (s *StoreRPCServer) SynthCoservQueryKeys(args SynthCoservQueryKeysArgs, resp *[]string) (err error) { - *resp, err = s.Impl.SynthCoservQueryKeys(args.TenantID, args.Query) - - return err -} - -/* - RPC client - (plugin caller side) -*/ - -type StoreRPCClient struct { - client *rpc.Client -} - -func (c StoreRPCClient) Close() error { - var ( - unused0 interface{} - unused1 interface{} - ) - - return c.client.Call("Plugin.Close", unused0, unused1) -} - -func (c StoreRPCClient) GetName() string { - var ( - err error - resp string - unused interface{} - ) - - err = c.client.Call("Plugin.GetName", &unused, &resp) - if err != nil { - return "" - } - - return resp -} - -func (c StoreRPCClient) GetAttestationScheme() string { - var ( - err error - resp string - unused interface{} - ) - - err = c.client.Call("Plugin.GetAttestationScheme", &unused, &resp) - if err != nil { - return "" - } - - return resp -} - -func (c StoreRPCClient) GetSupportedMediaTypes() []string { - var ( - err error - resp []string - unused interface{} - ) - - err = c.client.Call("Plugin.GetSupportedMediaTypes", &unused, &resp) - if err != nil { - return nil - } - - return resp -} - -func (c *StoreRPCClient) SynthKeysFromRefValue(tenantID string, refVal *Endorsement) ([]string, error) { - var ( - err error - resp []string - args SynthKeysArgs - ) - - args.TenantID = tenantID - - args.EndorsementJSON, err = json.Marshal(refVal) - if err != nil { - return nil, fmt.Errorf("marshaling reference value: %w", err) - } - - err = c.client.Call("Plugin.SynthKeysFromRefValue", args, &resp) - if err != nil { - err = ParseError(err) - return nil, fmt.Errorf("Plugin.SynthKeysFromRefValue RPC call failed: %w", err) // nolint - } - - return resp, nil -} - -func (c *StoreRPCClient) SynthKeysFromTrustAnchor(tenantID string, ta *Endorsement) ([]string, error) { - var ( - err error - resp []string - args SynthKeysArgs - ) - - args.TenantID = tenantID - - args.EndorsementJSON, err = json.Marshal(ta) - if err != nil { - return nil, fmt.Errorf("marshaling trust anchor: %w", err) - } - - err = c.client.Call("Plugin.SynthKeysFromTrustAnchor", args, &resp) - if err != nil { - err = ParseError(err) - return nil, fmt.Errorf("Plugin.SynthKeysFromTrustAnchor RPC call failed: %w", err) // nolint - } - - return resp, nil -} - -func (c *StoreRPCClient) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - var ( - err error - data []byte - resp []string - ) - - data, err = json.Marshal(token) - if err != nil { - return []string{""}, fmt.Errorf("marshaling token: %w", err) - } - - err = c.client.Call("Plugin.GetTrustAnchorIDs", data, &resp) - if err != nil { - err = ParseError(err) - return []string{""}, fmt.Errorf("Plugin.GetTrustAnchorIDs RPC call failed: %w", err) // nolint - } - - return resp, nil -} - -func (c *StoreRPCClient) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - var ( - err error - resp []string - ) - - args := GetRefValueIDsArgs{ - TenantID: tenantID, - TrustAnchors: trustAnchors, - } - - args.Claims, err = json.Marshal(claims) - if err != nil { - return nil, err - } - - err = c.client.Call("Plugin.GetRefValueIDs", args, &resp) - if err != nil { - err = ParseError(err) - return nil, fmt.Errorf("Plugin.GetRefValueIDs RPC call failed: %w", err) // nolint - } - - return resp, nil -} - -func (c *StoreRPCClient) SynthCoservQueryKeys( - tenantID string, - query string, -) (resp []string, err error) { - args := SynthCoservQueryKeysArgs{TenantID: tenantID, Query: query} - - if err = c.client.Call("Plugin.SynthCoservQueryKeys", args, &resp); err != nil { - return nil, fmt.Errorf("Plugin.SynthCoservQueryKeys RPC call failed: %w", ParseError(err)) - } - - return resp, nil -} diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 3ad627f7..ff3bd25a 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -35,7 +35,7 @@ image: .built/image $(SCHEME_DIR)tpm-enacttrust/test/cmd/gen-token/gen-token mkdir -p $(TESTER_CONTEXT) cp $(SCHEME_DIR)tpm-enacttrust/test/cmd/gen-token/gen-token $(TESTER_CONTEXT)/gen-enacttrust-token - cp $(DEPLOY_DEST)/utils/{cocli,evcli} $(TESTER_CONTEXT)/ + cp $(DEPLOY_DEST)/utils/{cocli,evcli,corim-store,corim-store-config.yaml} $(TESTER_CONTEXT)/ cp $(DEPLOY_DEST)/certs/rootCA.crt $(TESTER_CONTEXT)/ cp $(THIS_DIR)docker/* $(TESTER_CONTEXT)/ docker build -t veraison/test $(TESTER_CONTEXT) \ diff --git a/integration-tests/data/endorsements/corim-enacttrust-badta.cbor b/integration-tests/data/endorsements/corim-enacttrust-badta.cbor index bb497ebe4ace5164e7227ac75412e4a904065a55..6a32e7c3381648b2d9241085f16f0f93104d716c 100644 GIT binary patch delta 15 WcmZ3+xQuav4eL$DUlFMj9a8} int: def clear_stores(): - for prefix in ['en', 'po', 'ta']: - command = f"sqlite3 /opt/veraison/stores/vts/{prefix}-store.sql 'delete from kvstore'" - run_command(command, f'clear {prefix} store') + run_command('corim-store db clear', 'clear CoRIM store') + run_command( + "sqlite3 /opt/veraison/stores/vts/po-store.sql 'delete from kvstore'", + 'clear policy store', + ) def get_access_token(test, role): diff --git a/kvstore/sql.go b/kvstore/sql.go index 6db2dd3c..91456d74 100644 --- a/kvstore/sql.go +++ b/kvstore/sql.go @@ -1,4 +1,4 @@ -// Copyright 2021-2025 Contributors to the Veraison project. +// Copyright 2021-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package kvstore @@ -8,11 +8,10 @@ import ( "fmt" "regexp" + sq "github.com/Masterminds/squirrel" "github.com/spf13/viper" "github.com/veraison/services/config" "go.uber.org/zap" - sq "github.com/Masterminds/squirrel" - // drivers _ "github.com/go-sql-driver/mysql" // mysql @@ -20,7 +19,7 @@ import ( ) var ( - DefaultTableName = "kvstore" + DefaultTableName = "kvstore" DefaultMaxConnections = 10 ) @@ -49,8 +48,8 @@ func (o *sqlConfig) Validate() error { } type SQL struct { - TableName string - DB *sql.DB + TableName string + DB *sql.DB Placeholder sq.PlaceholderFormat logger *zap.SugaredLogger @@ -59,17 +58,22 @@ type SQL struct { // Init initializes the KVStore. The config may contain the following values, // all of which are optional: // "sql.tablename" - The name of the table with key-values pairs (defaults to -// "kvstore". +// +// "kvstore". +// // "sql.driver" - The SQL driver to use; see -// https://github.com/golang/go/wiki/SQLDrivers (defaults to -// "sqlite3"). +// +// https://github.com/golang/go/wiki/SQLDrivers (defaults to +// "sqlite3"). +// // "sql.datasource" - The name of the data source to use. Valid values are -// driver-specific (defaults to "db=veraison.sql". +// +// driver-specific (defaults to "db=veraison.sql". func (o *SQL) Init(v *viper.Viper, logger *zap.SugaredLogger) error { o.logger = logger cfg := sqlConfig{ - TableName: DefaultTableName, + TableName: DefaultTableName, MaxConnections: DefaultMaxConnections, } @@ -218,7 +222,7 @@ func (o SQL) Add(key string, val string) error { } query := sq.Insert(o.TableName).Columns("kv_key", "kv_val"). - Values(key, val).PlaceholderFormat(o.Placeholder) + Values(key, val).PlaceholderFormat(o.Placeholder) queryText, args, err := query.ToSql() if err != nil { @@ -250,8 +254,8 @@ func (o SQL) Set(key string, val string) error { defer func() { _ = txn.Rollback() }() delQuery := sq.Delete(o.TableName). - Where(sq.Eq{"kv_key": key}). - PlaceholderFormat(o.Placeholder) + Where(sq.Eq{"kv_key": key}). + PlaceholderFormat(o.Placeholder) queryText, args, err := delQuery.ToSql() if err != nil { @@ -263,8 +267,8 @@ func (o SQL) Set(key string, val string) error { } insQuery := sq.Insert(o.TableName).Columns("kv_key", "kv_val"). - Values(key, val). - PlaceholderFormat(o.Placeholder) + Values(key, val). + PlaceholderFormat(o.Placeholder) queryText, args, err = insQuery.ToSql() if err != nil { @@ -288,8 +292,8 @@ func (o SQL) Del(key string) error { } query := sq.Delete(o.TableName). - Where(sq.Eq{"kv_key": key}). - PlaceholderFormat(o.Placeholder) + Where(sq.Eq{"kv_key": key}). + PlaceholderFormat(o.Placeholder) queryText, args, err := query.ToSql() if err != nil { diff --git a/kvstore/sql_test.go b/kvstore/sql_test.go index 37d131f0..d48d0db7 100644 --- a/kvstore/sql_test.go +++ b/kvstore/sql_test.go @@ -1,4 +1,4 @@ -// Copyright 2021-2024 Contributors to the Veraison project. +// Copyright 2021-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package kvstore @@ -162,7 +162,7 @@ func TestSQL_Get_key_not_found(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} e := mock.ExpectQuery(regexp.QuoteMeta("SELECT DISTINCT kv_val FROM endorsement WHERE kv_key = ?")) e.WithArgs("ninja") @@ -183,7 +183,7 @@ func TestSQL_Get_broken_invariant_null_val_panic(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} rows := sqlmock.NewRows([]string{"kv_val"}) rows.AddRow(nil) @@ -211,7 +211,7 @@ func TestSQL_Get_ok(t *testing.T) { e.WithArgs("key") e.WillReturnRows(rows) - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} vals, err := s.Get("key") assert.NoError(t, err) @@ -234,7 +234,7 @@ func TestSQL_GetKeys_ok(t *testing.T) { e := mock.ExpectQuery(regexp.QuoteMeta("SELECT DISTINCT kv_key FROM endorsement")) e.WillReturnRows(rows) - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} keys, err := s.GetKeys() assert.NoError(t, err) @@ -250,7 +250,7 @@ func TestSQL_Set_empty_key(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} emptyKey := "" @@ -265,7 +265,7 @@ func TestSQL_Set_bad_val(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} invalidJSON := "" @@ -280,7 +280,7 @@ func TestSQL_Set_db_layer_delete_failure(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} dbErrorString := "a DB error" @@ -304,7 +304,7 @@ func TestSQL_Set_db_layer_insert_failure(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} dbErrorString := "a DB error" @@ -329,7 +329,7 @@ func TestSQL_Set_ok(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} mock.ExpectBegin() mock.ExpectExec(regexp.QuoteMeta("DELETE FROM endorsement WHERE kv_key = ?")). @@ -353,7 +353,7 @@ func TestSQL_Del_empty_key(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} emptyKey := "" @@ -368,7 +368,7 @@ func TestSQL_Del_db_layer_failure(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} dbErrorString := "a DB error" @@ -391,7 +391,7 @@ func TestSQL_Del_ok(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} e := mock.ExpectExec(regexp.QuoteMeta("DELETE FROM endorsement WHERE kv_key = ?")) e.WithArgs(testKey) @@ -410,7 +410,7 @@ func TestSQL_Del_key_not_found(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} e := mock.ExpectExec(regexp.QuoteMeta("DELETE FROM endorsement WHERE kv_key = ?")) e.WithArgs(testKey) @@ -432,7 +432,7 @@ func TestSQL_Add_empty_key(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} emptyKey := "" @@ -447,7 +447,7 @@ func TestSQL_Add_bad_val(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} invalidJSON := "" @@ -462,7 +462,7 @@ func TestSQL_Add_db_layer_failure(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} dbErrorString := "a DB error" @@ -485,7 +485,7 @@ func TestSQL_Add_ok(t *testing.T) { require.NoError(t, err) defer db.Close() - s := SQL{TableName: "endorsement", DB: db, Placeholder:sq.Question} + s := SQL{TableName: "endorsement", DB: db, Placeholder: sq.Question} mock.ExpectExec(regexp.QuoteMeta("INSERT INTO endorsement (kv_key,kv_val) VALUES (?,?)")). WithArgs(testKey, testVal). diff --git a/log/log.go b/log/log.go index d366f369..583c33c7 100644 --- a/log/log.go +++ b/log/log.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package log @@ -45,12 +45,12 @@ var supportedEncodings = map[string]bool{ "json": true, } -// Fully exposing encoder configuration in Veraison config is going to be a -// lot of hassle (need to provide mapstructure serialisation for all the -// underlying encoders; and, arguably, would be unwieldy for the end-user. On -// the other hand, it may be useful to have different formatting in different -// contexts. As a middle ground, allow selecting between pre-defined formats -// in the config rather than exposing all the individual settings. +// Fully exposing encoder configuration in Veraison config is going to be a +// lot of hassle (need to provide mapstructure serialisation for all the +// underlying encoders; and, arguably, would be unwieldy for the end-user. On +// the other hand, it may be useful to have different formatting in different +// contexts. As a middle ground, allow selecting between pre-defined formats +// in the config rather than exposing all the individual settings. var encoderConfigs = map[string]zapcore.EncoderConfig{ "production": zap.NewProductionEncoderConfig(), "development": zap.NewDevelopmentEncoderConfig(), diff --git a/management/api/router.go b/management/api/router.go index cf29c596..a8f5532e 100644 --- a/management/api/router.go +++ b/management/api/router.go @@ -1,4 +1,4 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package api @@ -40,7 +40,7 @@ func NewRouter(handler Handler, authorizer auth.IAuthorizer) *gin.Engine { manageGroup.POST("policies/:scheme/deactivate", handler.DeactivateAll) publicApiMap["deactivatePolicies"] = path.Join(managementPath, - "policies/:scheme/deactivate") + "policies/:scheme/deactivate") manageGroup.GET("policies/:scheme", handler.GetPolicies) publicApiMap["getPolicies"] = path.Join(managementPath, "policies/:scheme") diff --git a/management/cmd/management-service/main.go b/management/cmd/management-service/main.go index 7f27f70b..e19b3ef6 100644 --- a/management/cmd/management-service/main.go +++ b/management/cmd/management-service/main.go @@ -1,4 +1,4 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -51,9 +51,9 @@ func main() { cfg := cfg{ ListenAddr: DefaultListenAddr, - Protocol: "https", - Cert: "[unset]", - CertKey: "[unset]", + Protocol: "https", + Cert: "[unset]", + CertKey: "[unset]", } loader := config.NewLoader(&cfg) if err := loader.LoadFromViper(subs["management"]); err != nil { diff --git a/management/policy.go b/management/policy.go index 891710af..1f9781b5 100644 --- a/management/policy.go +++ b/management/policy.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package management @@ -39,18 +39,18 @@ func CreatePolicyManagerFromConfig(v *viper.Viper, name string) (*PolicyManager, return nil, err } - var pluginManager plugin.IManager[handler.IEvidenceHandler] + var pluginManager plugin.IManager[handler.ISchemeHandler] if config.SchemeLoader == "plugins" { // nolint:gocritic pluginManager, err = plugin.CreateGoPluginManager( subs["plugin"], log.Named("plugin"), - "evidence-handler", handler.EvidenceHandlerRPC) + "scheme-handler", handler.SchemeHandlerRPC) if err != nil { log.Fatalf("plugin manager initialization failed: %v", err) } } else if config.SchemeLoader == "builtin" { - pluginManager, err = builtin.CreateBuiltinManager[handler.IEvidenceHandler]( - subs["plugin"], log.Named("builtin"), "evidence-handler") + pluginManager, err = builtin.CreateBuiltinManager[handler.ISchemeHandler]( + subs["plugin"], log.Named("builtin"), "scheme-handler") if err != nil { log.Fatalf("scheme manager initialization failed: %v", err) } diff --git a/mk/test.mk b/mk/test.mk index 2005b4ff..a64f667f 100644 --- a/mk/test.mk +++ b/mk/test.mk @@ -11,7 +11,7 @@ TEST_ARGS ?= -v -cover -race MOCKGEN := $(shell go env GOPATH)/bin/mockgen -COPYRIGHT_FLAGS ?= +COPYRIGHT_FLAGS ?= --ignore \*scheme/example\* define MOCK_template mock_$(1): $(1) diff --git a/plugin/goplugin_context.go b/plugin/goplugin_context.go index 727c46f1..f8ff2cb9 100644 --- a/plugin/goplugin_context.go +++ b/plugin/goplugin_context.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package plugin @@ -35,7 +35,7 @@ type PluginContext[I IPluggable] struct { Scheme string // SupportedMediaTypes are the types of input this plugin can process. // This is is the method by which a plugin is selected. - SupportedMediaTypes []string + SupportedMediaTypes map[string][]string // Handle is actual RPC interface to the plugin implementation. Handle I diff --git a/plugin/goplugin_loader.go b/plugin/goplugin_loader.go index fe2a0afd..e4f64dbb 100644 --- a/plugin/goplugin_loader.go +++ b/plugin/goplugin_loader.go @@ -1,4 +1,4 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package plugin @@ -163,18 +163,20 @@ func DiscoverGoPluginUsing[I IPluggable](o *GoPluginLoader) error { } o.loadedByName[pluginName] = pluginContext - for _, mediaType := range pluginContext.SupportedMediaTypes { - if existing, ok := o.loadedByMediaType[mediaType]; ok { - return fmt.Errorf( - "plugins %q [%s] and %q [%s] both provides support for %q", - existing.GetName(), - existing.GetPath(), - pluginContext.GetName(), - pluginContext.GetPath(), - mediaType, - ) + for _, mediaTypes := range pluginContext.SupportedMediaTypes { + for _, mediaType := range mediaTypes { + if existing, ok := o.loadedByMediaType[mediaType]; ok { + return fmt.Errorf( + "plugins %q [%s] and %q [%s] both provides support for %q", + existing.GetName(), + existing.GetPath(), + pluginContext.GetName(), + pluginContext.GetPath(), + mediaType, + ) + } + o.loadedByMediaType[mediaType] = pluginContext } - o.loadedByMediaType[mediaType] = pluginContext } } diff --git a/plugin/goplugin_manager.go b/plugin/goplugin_manager.go index 5cf259e1..134afd86 100644 --- a/plugin/goplugin_manager.go +++ b/plugin/goplugin_manager.go @@ -1,9 +1,10 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package plugin import ( "errors" + "slices" "github.com/spf13/viper" "go.uber.org/zap" @@ -74,12 +75,7 @@ func (o *GoPluginManager[I]) Close() error { func (o *GoPluginManager[I]) IsRegisteredMediaType(mediaType string) bool { mts := o.GetRegisteredMediaTypes() - for _, mt := range mts { - if mt == mediaType { - return true - } - } - return false + return slices.Contains(mts, mediaType) } func (o *GoPluginManager[I]) GetRegisteredMediaTypes() []string { @@ -94,6 +90,21 @@ func (o *GoPluginManager[I]) GetRegisteredMediaTypes() []string { return registeredMediatTypes } +func (o *GoPluginManager[I]) GetRegisteredMediaTypesByCategory(category string) []string { + var registeredMediatTypes []string + + for _, pc := range o.loader.loadedByName { + if pluggable, ok := pc.GetHandle().(I); ok { + mts, ok := pluggable.GetSupportedMediaTypes()[category] + if ok { + registeredMediatTypes = append(registeredMediatTypes, mts...) + } + } + } + + return registeredMediatTypes +} + func (o *GoPluginManager[I]) GetRegisteredAttestationSchemes() []string { return GetGoPluginLoadedAttestationSchemes[I](o.loader) } diff --git a/plugin/imanager.go b/plugin/imanager.go index 12591445..9198300d 100644 --- a/plugin/imanager.go +++ b/plugin/imanager.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package plugin @@ -23,6 +23,10 @@ type IManager[I IPluggable] interface { // been registered with the manager by discovered plugins. GetRegisteredMediaTypes() []string + // GetRegisteredMediaTypesByCategory returns a []string of media types + // that have been registered with the manager by discovered plugins. + GetRegisteredMediaTypesByCategory(category string) []string + // GetRegisteredAttestationSchemes returns a []string of names for // schemes that have been registered with the manager by discovered // plugins. diff --git a/plugin/ipluggable.go b/plugin/ipluggable.go index a9e0ce05..3d146b6f 100644 --- a/plugin/ipluggable.go +++ b/plugin/ipluggable.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package plugin @@ -14,7 +14,8 @@ type IPluggable interface { // attestation scheme handled by this IPluggable implementation. GetAttestationScheme() string - // GetSupportedMediaTypes returns a []string containing the media types - // this plugin is capable of handling. - GetSupportedMediaTypes() []string + // GetSupportedMediaTypes returns a map[string][]string that maps + // cetegory names to the the media types in that category that this + // plugin is capable of handling. + GetSupportedMediaTypes() map[string][]string } diff --git a/plugin/test/ammo.go b/plugin/test/ammo.go index fde07631..d5f80f01 100644 --- a/plugin/test/ammo.go +++ b/plugin/test/ammo.go @@ -1,8 +1,9 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package test // nolint:dupl import ( + "encoding/json" "log" "net/rpc" @@ -12,7 +13,7 @@ import ( type IAmmo interface { GetName() string GetAttestationScheme() string - GetSupportedMediaTypes() []string + GetSupportedMediaTypes() map[string][]string GetCapacity() int } @@ -23,7 +24,7 @@ type AmmoRPCClient struct { func (o *AmmoRPCClient) GetName() string { var ( resp string - unused interface{} + unused any ) err := o.client.Call("Plugin.GetName", &unused, &resp) @@ -38,7 +39,7 @@ func (o *AmmoRPCClient) GetName() string { func (o *AmmoRPCClient) GetAttestationScheme() string { var ( resp string - unused interface{} + unused any ) err := o.client.Call("Plugin.GetAttestationScheme", &unused, &resp) @@ -50,10 +51,10 @@ func (o *AmmoRPCClient) GetAttestationScheme() string { return resp } -func (o *AmmoRPCClient) GetSupportedMediaTypes() []string { +func (o *AmmoRPCClient) GetSupportedMediaTypes() map[string][]string { var ( - resp []string - unused interface{} + resp []byte + unused any ) err := o.client.Call("Plugin.GetSupportedMediaTypes", &unused, &resp) @@ -62,13 +63,18 @@ func (o *AmmoRPCClient) GetSupportedMediaTypes() []string { return nil } - return resp + var res map[string][]string + if err := json.Unmarshal(resp, &res); err != nil { + panic(err) + } + + return res } func (o *AmmoRPCClient) GetCapacity() int { var ( resp int - unused interface{} + unused any ) err := o.client.Call("Plugin.GetCapacity", &unused, &resp) @@ -84,31 +90,34 @@ type AmmoRPCServer struct { Impl IAmmo } -func (o *AmmoRPCServer) GetName(args interface{}, resp *string) error { +func (o *AmmoRPCServer) GetName(args any, resp *string) error { *resp = o.Impl.GetName() return nil } -func (o *AmmoRPCServer) GetAttestationScheme(args interface{}, resp *string) error { +func (o *AmmoRPCServer) GetAttestationScheme(args any, resp *string) error { *resp = o.Impl.GetAttestationScheme() return nil } -func (o *AmmoRPCServer) GetSupportedMediaTypes(args interface{}, resp *[]string) error { - *resp = o.Impl.GetSupportedMediaTypes() - return nil +func (o *AmmoRPCServer) GetSupportedMediaTypes(args any, resp *[]byte) error { + var err error + + *resp, err = json.Marshal(o.Impl.GetSupportedMediaTypes()) + + return err } -func (o *AmmoRPCServer) GetCapacity(args interface{}, resp *int) error { +func (o *AmmoRPCServer) GetCapacity(args any, resp *int) error { *resp = o.Impl.GetCapacity() return nil } -func GetAmmoClient(c *rpc.Client) interface{} { +func GetAmmoClient(c *rpc.Client) any { return &AmmoRPCClient{client: c} } -func GetAmmoServer(i IAmmo) interface{} { +func GetAmmoServer(i IAmmo) any { return &AmmoRPCServer{Impl: i} } diff --git a/plugin/test/gascartridge/gascartridge.go b/plugin/test/gascartridge/gascartridge.go index 8ade80c8..68d1b238 100644 --- a/plugin/test/gascartridge/gascartridge.go +++ b/plugin/test/gascartridge/gascartridge.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -18,8 +18,8 @@ func (o GasCartridge) GetAttestationScheme() string { return "star-wars" } -func (o GasCartridge) GetSupportedMediaTypes() []string { - return []string{"tibanna gas"} +func (o GasCartridge) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{"ammo": {"tibanna gas"}} } func (o GasCartridge) GetCapacity() int { diff --git a/plugin/test/mook.go b/plugin/test/mook.go index e1d350be..3c744323 100644 --- a/plugin/test/mook.go +++ b/plugin/test/mook.go @@ -1,8 +1,9 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package test // nolint:dupl import ( + "encoding/json" "log" "net/rpc" @@ -12,7 +13,7 @@ import ( type IMook interface { GetName() string GetAttestationScheme() string - GetSupportedMediaTypes() []string + GetSupportedMediaTypes() map[string][]string Shoot() string } @@ -23,7 +24,7 @@ type MookRPCClient struct { func (o *MookRPCClient) GetName() string { var ( resp string - unused interface{} + unused any ) err := o.client.Call("Plugin.GetName", &unused, &resp) @@ -38,7 +39,7 @@ func (o *MookRPCClient) GetName() string { func (o *MookRPCClient) GetAttestationScheme() string { var ( resp string - unused interface{} + unused any ) err := o.client.Call("Plugin.GetAttestationScheme", &unused, &resp) @@ -50,10 +51,10 @@ func (o *MookRPCClient) GetAttestationScheme() string { return resp } -func (o *MookRPCClient) GetSupportedMediaTypes() []string { +func (o *MookRPCClient) GetSupportedMediaTypes() map[string][]string { var ( - resp []string - unused interface{} + resp []byte + unused any ) err := o.client.Call("Plugin.GetSupportedMediaTypes", &unused, &resp) @@ -62,13 +63,18 @@ func (o *MookRPCClient) GetSupportedMediaTypes() []string { return nil } - return resp + var res map[string][]string + if err := json.Unmarshal(resp, &res); err != nil { + panic(err) + } + + return res } func (o *MookRPCClient) Shoot() string { var ( resp string - unused interface{} + unused any ) err := o.client.Call("Plugin.Shoot", &unused, &resp) @@ -84,31 +90,34 @@ type MookRPCServer struct { Impl IMook } -func (o *MookRPCServer) GetName(args interface{}, resp *string) error { +func (o *MookRPCServer) GetName(args any, resp *string) error { *resp = o.Impl.GetName() return nil } -func (o *MookRPCServer) GetAttestationScheme(args interface{}, resp *string) error { +func (o *MookRPCServer) GetAttestationScheme(args any, resp *string) error { *resp = o.Impl.GetAttestationScheme() return nil } -func (o *MookRPCServer) GetSupportedMediaTypes(args interface{}, resp *[]string) error { - *resp = o.Impl.GetSupportedMediaTypes() - return nil +func (o *MookRPCServer) GetSupportedMediaTypes(args any, resp *[]byte) error { + var err error + + *resp, err = json.Marshal(o.Impl.GetSupportedMediaTypes()) + + return err } -func (o *MookRPCServer) Shoot(args interface{}, resp *string) error { +func (o *MookRPCServer) Shoot(args any, resp *string) error { *resp = o.Impl.Shoot() return nil } -func GetMookClient(c *rpc.Client) interface{} { +func GetMookClient(c *rpc.Client) any { return &MookRPCClient{client: c} } -func GetMookServer(i IMook) interface{} { +func GetMookServer(i IMook) any { return &MookRPCServer{Impl: i} } diff --git a/plugin/test/powercell/powercell.go b/plugin/test/powercell/powercell.go index e2e2a930..32b7f0b5 100644 --- a/plugin/test/powercell/powercell.go +++ b/plugin/test/powercell/powercell.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -18,8 +18,8 @@ func (o PowerCell) GetAttestationScheme() string { return "star-trek" } -func (o PowerCell) GetSupportedMediaTypes() []string { - return []string{"plasma"} +func (o PowerCell) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{"ammo": {"plasma"}} } func (o PowerCell) GetCapacity() int { diff --git a/plugin/test/redshirt/redshirt.go b/plugin/test/redshirt/redshirt.go index d86405bf..aeb3ed7a 100644 --- a/plugin/test/redshirt/redshirt.go +++ b/plugin/test/redshirt/redshirt.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -18,8 +18,8 @@ func (o RedShirt) GetAttestationScheme() string { return "star-trek" } -func (o RedShirt) GetSupportedMediaTypes() []string { - return []string{"phaser"} +func (o RedShirt) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{"mook": {"phaser"}} } func (o RedShirt) Shoot() string { diff --git a/plugin/test/trooper/trooper.go b/plugin/test/trooper/trooper.go index eddbb45e..0b83c55d 100644 --- a/plugin/test/trooper/trooper.go +++ b/plugin/test/trooper/trooper.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -18,8 +18,8 @@ func (o ImperialTrooper) GetAttestationScheme() string { return "star-wars" } -func (o ImperialTrooper) GetSupportedMediaTypes() []string { - return []string{"blaster"} +func (o ImperialTrooper) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{"mook": {"blaster"}} } func (o ImperialTrooper) Shoot() string { diff --git a/policy/agent.go b/policy/agent.go index 9d15644f..1f062dd3 100644 --- a/policy/agent.go +++ b/policy/agent.go @@ -1,15 +1,17 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policy import ( "context" + "encoding/json" "fmt" "github.com/spf13/viper" + "github.com/veraison/corim/comid" "github.com/veraison/ear" "github.com/veraison/services/config" - "github.com/veraison/services/proto" + "github.com/veraison/services/vts/appraisal" "go.uber.org/zap" ) @@ -68,26 +70,30 @@ func (o *Agent) GetBackendName() string { // overwrite the result status or any of the values in the result trust vector. func (o *Agent) Evaluate( ctx context.Context, - sessionContext map[string]interface{}, - scheme string, + sessionContext map[string]any, + appraisalContext *appraisal.Context, policy *Policy, submod string, appraisal *ear.Appraisal, - evidence *proto.EvidenceContext, - endorsements []string, + endorsements []*comid.ValueTriple, ) (*ear.Appraisal, error) { + endorsementMaps, err := endorsementsToMaps(endorsements) + if err != nil { + return nil, err + } + resultMap := appraisal.AsMap() appraisalUpdated := false updatedByPolicy, err := o.Backend.Evaluate( ctx, sessionContext, - scheme, + appraisalContext.Scheme, policy.Rules, resultMap, - evidence.Evidence.AsMap(), - endorsements, + appraisalContext.Claims, + endorsementMaps, ) if err != nil { return nil, fmt.Errorf("could not evaluate policy: %w", err) @@ -153,3 +159,23 @@ func (o *Agent) GetBackend() IBackend { func (o *Agent) Close() { o.Backend.Close() } + +func endorsementsToMaps(endorsemetTriples []*comid.ValueTriple) ([]map[string]any, error) { + ret := make([]map[string]any, len(endorsemetTriples)) + + for i, et := range endorsemetTriples { + endorsementJSON, err := json.Marshal(et) + if err != nil { + return nil, fmt.Errorf("endorsement at index %d: %w", i, err) + } + + var endorsement map[string]any + if err := json.Unmarshal(endorsementJSON, &endorsement); err != nil { + return nil, fmt.Errorf("endorsement at index %d: %w", i, err) + } + + ret[i] = endorsement + } + + return ret, nil +} diff --git a/policy/agent_test.go b/policy/agent_test.go index c0fc0456..6d25bd95 100644 --- a/policy/agent_test.go +++ b/policy/agent_test.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policy @@ -11,10 +11,11 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/veraison/corim/comid" "github.com/veraison/ear" "github.com/veraison/services/log" mock_deps "github.com/veraison/services/policy/mocks" - "github.com/veraison/services/proto" + "github.com/veraison/services/vts/appraisal" ) func Test_CreateAgent(t *testing.T) { @@ -36,7 +37,7 @@ func Test_CreateAgent(t *testing.T) { type AgentEvaluateTestVector struct { Name string ExpectedError string - ReturnAppraisal map[string]interface{} + ReturnAppraisal map[string]any ReturnError error ExpectedAppraisal *ear.Appraisal } @@ -47,9 +48,9 @@ func Test_Agent_Evaluate(t *testing.T) { vectors := []AgentEvaluateTestVector{ { Name: "success", - ReturnAppraisal: map[string]interface{}{ + ReturnAppraisal: map[string]any{ "ear.status": 2, - "ear.trustworthiness-vector": map[string]interface{}{ + "ear.trustworthiness-vector": map[string]any{ "instance-identity": 0, "configuration": 0, "executables": 2, // AFFIRMING @@ -71,9 +72,9 @@ func Test_Agent_Evaluate(t *testing.T) { }, { Name: "bad status", - ReturnAppraisal: map[string]interface{}{ + ReturnAppraisal: map[string]any{ "ear.status": "MEH", - "ear.trustworthiness-vector": map[string]interface{}{ + "ear.trustworthiness-vector": map[string]any{ "instance-identity": 0, "configuration": 0, "executables": 2, // AFFIRMING @@ -90,8 +91,8 @@ func Test_Agent_Evaluate(t *testing.T) { }, { Name: "bad result, no status", - ReturnAppraisal: map[string]interface{}{ - "ear.trustworthiness-vector": map[string]interface{}{ + ReturnAppraisal: map[string]any{ + "ear.trustworthiness-vector": map[string]any{ "instance-identity": 0, "configuration": 0, "executables": 2, // AFFIRMING @@ -108,7 +109,7 @@ func Test_Agent_Evaluate(t *testing.T) { }, { Name: "bad result, no trust vector", - ReturnAppraisal: map[string]interface{}{ + ReturnAppraisal: map[string]any{ "ear.status": "affirming", }, ReturnError: nil, @@ -117,9 +118,9 @@ func Test_Agent_Evaluate(t *testing.T) { }, { Name: "bad result, bad trust vector", - ReturnAppraisal: map[string]interface{}{ + ReturnAppraisal: map[string]any{ "ear.status": 2, - "ear.trustworthiness-vector": map[string]interface{}{ + "ear.trustworthiness-vector": map[string]any{ "instance-identity": 0, "configuration": 0, "executables": 2, // AFFIRMING @@ -146,15 +147,15 @@ func Test_Agent_Evaluate(t *testing.T) { Rules: "", } - var endorsements []string + endorsements := []*comid.ValueTriple{} contraStatus := ear.TrustTierContraindicated polID := "policy:test-scheme" + appraisalContext := &appraisal.Context{} appraisal := &ear.Appraisal{ Status: &contraStatus, TrustVector: &ear.TrustVector{}, AppraisalPolicyID: &polID, } - evidence := &proto.EvidenceContext{} logger := log.Named("test") @@ -169,14 +170,20 @@ func Test_Agent_Evaluate(t *testing.T) { gomock.Eq(policy.Rules), gomock.Any(), gomock.Any(), - gomock.Eq(endorsements)). + gomock.Eq([]map[string]any{})). AnyTimes(). Return(v.ReturnAppraisal, v.ReturnError) agent := &Agent{Backend: backend, logger: logger} - submod := "test" - res, err := agent.Evaluate(ctx, map[string]interface{}{}, "test", policy, - submod, appraisal, evidence, endorsements) + res, err := agent.Evaluate( + ctx, + map[string]any{}, + appraisalContext, + policy, + "test", + appraisal, + endorsements, + ) if v.ExpectedError == "" { require.NoError(t, err) diff --git a/policy/iagent.go b/policy/iagent.go index 77ad8983..4dbae479 100644 --- a/policy/iagent.go +++ b/policy/iagent.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policy @@ -6,21 +6,21 @@ import ( "context" "github.com/spf13/viper" + "github.com/veraison/corim/comid" "github.com/veraison/ear" - "github.com/veraison/services/proto" + "github.com/veraison/services/vts/appraisal" ) type IAgent interface { Init(v *viper.Viper) error GetBackendName() string Evaluate(ctx context.Context, - appraisalContext map[string]interface{}, - scheme string, + sessionContext map[string]any, + appraisalContext *appraisal.Context, policy *Policy, submod string, appraisal *ear.Appraisal, - evidence *proto.EvidenceContext, - endorsements []string, + endorsements []*comid.ValueTriple, ) (*ear.Appraisal, error) Validate(ctx context.Context, policyRules string) error Close() diff --git a/policy/ibackend.go b/policy/ibackend.go index 77afbf6e..7f5a0d50 100644 --- a/policy/ibackend.go +++ b/policy/ibackend.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policy @@ -13,13 +13,13 @@ type IBackend interface { GetName() string Evaluate( ctx context.Context, - sessionContext map[string]interface{}, + sessionContext map[string]any, scheme string, policy string, - result map[string]interface{}, - evidence map[string]interface{}, - endorsements []string, - ) (map[string]interface{}, error) + result map[string]any, + evidence map[string]any, + endorsements []map[string]any, + ) (map[string]any, error) Validate(ctx context.Context, policy string) error Close() } diff --git a/policy/mocks/mock_ibackend.go b/policy/mocks/mock_ibackend.go index 69ce2c55..57c3dee3 100644 --- a/policy/mocks/mock_ibackend.go +++ b/policy/mocks/mock_ibackend.go @@ -48,10 +48,10 @@ func (mr *MockIBackendMockRecorder) Close() *gomock.Call { } // Evaluate mocks base method. -func (m *MockIBackend) Evaluate(ctx context.Context, sessionContext map[string]interface{}, scheme, policy string, result, evidence map[string]interface{}, endorsements []string) (map[string]interface{}, error) { +func (m *MockIBackend) Evaluate(ctx context.Context, sessionContext map[string]any, scheme, policy string, result, evidence map[string]any, endorsements []map[string]any) (map[string]any, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Evaluate", ctx, sessionContext, scheme, policy, result, evidence, endorsements) - ret0, _ := ret[0].(map[string]interface{}) + ret0, _ := ret[0].(map[string]any) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/policy/opa.go b/policy/opa.go index e409340f..723b54f3 100644 --- a/policy/opa.go +++ b/policy/opa.go @@ -1,11 +1,10 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policy import ( "context" _ "embed" - "encoding/json" "errors" "fmt" @@ -41,17 +40,20 @@ func (o *OPA) GetName() string { func (o *OPA) Evaluate( ctx context.Context, - sessionContext map[string]interface{}, + sessionContext map[string]any, scheme string, policy string, - result map[string]interface{}, - evidence map[string]interface{}, - endorsements []string, + result map[string]any, + evidence map[string]any, + endorsements []map[string]any, ) (map[string]interface{}, error) { - input, err := constructInput(scheme, sessionContext, result, evidence, endorsements) - if err != nil { - return nil, fmt.Errorf("could not construct policy input: %w", err) + input := map[string]any{ + "scheme": scheme, + "session": sessionContext, + "result": result, + "evidence": evidence, + "endorsements": endorsements, } rego := rego.New( @@ -95,34 +97,6 @@ func (o *OPA) Validate(ctx context.Context, policy string) error { func (o *OPA) Close() { } -func constructInput( - scheme string, - sessionContext map[string]interface{}, - result map[string]interface{}, - evidence map[string]interface{}, - endorsementStrings []string, -) (map[string]interface{}, error) { - var endorsements []map[string]interface{} // nolint:prealloc - - for i, es := range endorsementStrings { - var e map[string]interface{} - - if err := json.Unmarshal([]byte(es), &e); err != nil { - return nil, fmt.Errorf("endorsement %d is not valid JSON: %w", i, err) - } - - endorsements = append(endorsements, e) - } - - return map[string]interface{}{ - "scheme": scheme, - "session": sessionContext, - "result": result, - "evidence": evidence, - "endorsements": endorsements, - }, nil -} - func processUpdateValue(value interface{}) (map[string]interface{}, error) { rawUpdate, ok := value.(map[string]interface{}) if !ok { diff --git a/policy/opa_test.go b/policy/opa_test.go index e8357519..5f9666aa 100644 --- a/policy/opa_test.go +++ b/policy/opa_test.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policy @@ -37,14 +37,14 @@ func (o EvaluateTestVector) Run(t *testing.T, ctx context.Context, pa *OPA) { evidenceMap, err := jsonFileToMap(o.EvidencePath) require.NoError(t, err) - endorsements, err := jsonFileToStringSlice(o.EndorsementsPath) + endorsements, err := jsonFileToMapSlice(o.EndorsementsPath) require.NoError(t, err) policy, err := os.ReadFile(o.PolicyPath) require.NoError(t, err) - res, err := pa.Evaluate(ctx, map[string]interface{}{}, o.Scheme, string(policy), - resultMap, evidenceMap["evidence"].(map[string]interface{}), endorsements) + res, err := pa.Evaluate(ctx, map[string]any{}, o.Scheme, string(policy), + resultMap, evidenceMap["evidence"].(map[string]any), endorsements) if o.Expected.Error == "" { require.NoError(t, err) } else { @@ -109,6 +109,7 @@ func Test_OPA_Evaluate(t *testing.T) { for _, v := range vectors { fmt.Printf("running %q\n", v.Title) v.Run(t, ctx, pa) + } } @@ -134,13 +135,13 @@ func Test_OPA_Validate(t *testing.T) { } } -func jsonFileToMap(path string) (map[string]interface{}, error) { +func jsonFileToMap(path string) (map[string]any, error) { bytes, err := os.ReadFile(path) if err != nil { return nil, err } - var result map[string]interface{} + var result map[string]any err = json.Unmarshal(bytes, &result) if err != nil { @@ -150,7 +151,7 @@ func jsonFileToMap(path string) (map[string]interface{}, error) { return result, nil } -func jsonFileToResultMap(path string) (map[string]interface{}, error) { +func jsonFileToResultMap(path string) (map[string]any, error) { bytes, err := os.ReadFile(path) if err != nil { return nil, err @@ -165,22 +166,21 @@ func jsonFileToResultMap(path string) (map[string]interface{}, error) { return result.AsMap(), nil } -func jsonFileToStringSlice(path string) ([]string, error) { +func jsonFileToMapSlice(path string) ([]map[string]any, error) { bytes, err := os.ReadFile(path) if err != nil { return nil, err } - var result []string - err = json.Unmarshal(bytes, &result) - if err != nil { + var ret []map[string]any + if err = json.Unmarshal(bytes, &ret); err != nil { return nil, err } - return result, nil + return ret, nil } -func getUpdateMap(ar *ear.AttestationResult) map[string]interface{} { +func getUpdateMap(ar *ear.AttestationResult) map[string]any { if ar == nil { return nil } @@ -189,9 +189,9 @@ func getUpdateMap(ar *ear.AttestationResult) map[string]interface{} { app := ar.Submods["test"] - return map[string]interface{}{ + return map[string]any{ "ear.status": &status, - "ear.trustworthiness-vector": map[string]interface{}{ + "ear.trustworthiness-vector": map[string]any{ "instance-identity": app.TrustVector.InstanceIdentity, "configuration": app.TrustVector.Configuration, "executables": app.TrustVector.Executables, diff --git a/policy/test/evaluate-vectors.json b/policy/test/evaluate-vectors.json index 83992554..786f2e0a 100644 --- a/policy/test/evaluate-vectors.json +++ b/policy/test/evaluate-vectors.json @@ -4,7 +4,7 @@ "scheme": "PSA_IOT", "result": "test/inputs/psa-result.json", "evidence": "test/inputs/psa-evidence.json", - "endorsements": "test/inputs/psa-endorsements.json", + "endorsements": "test/inputs/empty-endorsements.json", "policy": "test/policies/malformed.rego", "expected": { "error": "could not Eval policy: 1 error occurred: policy.rego:1: rego_parse_error: unexpected : token\n\tbad_rule:;;\n\t ^", @@ -16,7 +16,7 @@ "scheme": "PSA_IOT", "result": "test/inputs/psa-result.json", "evidence": "test/inputs/psa-evidence.json", - "endorsements": "test/inputs/psa-endorsements.json", + "endorsements": "test/inputs/empty-endorsements.json", "policy": "test/policies/bad.rego", "expected": { "error": "could not Eval policy: 1 error occurred: policy.rego:6: rego_unsafe_var_error: var y is unsafe", @@ -28,7 +28,7 @@ "scheme": "PSA_IOT", "result": "test/inputs/psa-result.json", "evidence": "test/inputs/psa-evidence.json", - "endorsements": "test/inputs/psa-endorsements.json", + "endorsements": "test/inputs/empty-endorsements.json", "policy": "test/policies/incorrect-rule-value.rego", "expected": { "error": "bad value \"SURE\" for \"executables\"", @@ -40,7 +40,7 @@ "scheme": "PSA_IOT", "result": "test/inputs/psa-result.json", "evidence": "test/inputs/psa-evidence.json", - "endorsements": "test/inputs/psa-endorsements.json", + "endorsements": "test/inputs/empty-endorsements.json", "policy": "test/policies/empty.rego", "expected": { "error": null, @@ -75,7 +75,7 @@ "scheme": "TPM_ENACTTRUST", "result": "test/inputs/enacttrust-result.json", "evidence": "test/inputs/enacttrust-evidence.json", - "endorsements": "test/inputs/enacttrust-endorsements.json", + "endorsements": "test/inputs/empty-endorsements.json", "policy": "test/policies/sw-up-to-dateness.rego", "expected": { "error": null, @@ -110,7 +110,7 @@ "scheme": "TPM_ENACTTRUST", "result": "test/inputs/enacttrust-result.json", "evidence": "test/inputs/enacttrust-evidence-updatedFirmware.json", - "endorsements": "test/inputs/enacttrust-endorsements.json", + "endorsements": "test/inputs/empty-endorsements.json", "policy": "test/policies/sw-up-to-dateness.rego", "expected": { "error": null, diff --git a/policy/test/inputs/enacttrust-endorsements.json b/policy/test/inputs/empty-endorsements.json similarity index 100% rename from policy/test/inputs/enacttrust-endorsements.json rename to policy/test/inputs/empty-endorsements.json diff --git a/policy/test/inputs/parsec-cca-endorsements.json b/policy/test/inputs/parsec-cca-endorsements.json index f008ff78..f69c2b5d 100644 --- a/policy/test/inputs/parsec-cca-endorsements.json +++ b/policy/test/inputs/parsec-cca-endorsements.json @@ -1,7 +1,74 @@ [ - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"PARSEC_CCA.sw-component\",\"attributes\":{\"PARSEC_CCA.hw-model\":\"RoadRunner\",\"PARSEC_CCA.hw-vendor\":\"ACME\",\"PARSEC_CCA.impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"PARSEC_CCA.measurement-desc\":\"sha-256\",\"PARSEC_CCA.measurement-type\":\"BL\",\"PARSEC_CCA.measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.version\":\"3.4.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"PARSEC_CCA.sw-component\",\"attributes\":{\"PARSEC_CCA.hw-model\":\"RoadRunner\",\"PARSEC_CCA.hw-vendor\":\"ACME\",\"PARSEC_CCA.impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"PARSEC_CCA.measurement-desc\":\"sha-256\",\"PARSEC_CCA.measurement-type\":\"M1\",\"PARSEC_CCA.measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.version\":\"1.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"PARSEC_CCA.sw-component\",\"attributes\":{\"PARSEC_CCA.hw-model\":\"RoadRunner\",\"PARSEC_CCA.hw-vendor\":\"ACME\",\"PARSEC_CCA.impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"PARSEC_CCA.measurement-desc\":\"sha-256\",\"PARSEC_CCA.measurement-type\":\"M2\",\"PARSEC_CCA.measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.version\":\"1.2.3\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"PARSEC_CCA.sw-component\",\"attributes\":{\"PARSEC_CCA.hw-model\":\"RoadRunner\",\"PARSEC_CCA.hw-vendor\":\"ACME\",\"PARSEC_CCA.impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"PARSEC_CCA.measurement-desc\":\"sha-256\",\"PARSEC_CCA.measurement-type\":\"M3\",\"PARSEC_CCA.measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"PARSEC_CCA.version\":\"1\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"PARSEC_CCA.platform-config\",\"attributes\":{\"PARSEC_CCA.hw-model\":\"RoadRunner\",\"PARSEC_CCA.hw-vendor\":\"ACME\",\"PARSEC_CCA.impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"PARSEC_CCA.platform-config-label\": \"platform-config-label\",\"PARSEC_CCA.platform-config-id\": \"AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY\"}}" -] \ No newline at end of file + { + "scheme": "PARSEC_CCA", + "type": "REFERENCE_VALUE", + "subType": "PARSEC_CCA.sw-component", + "attributes": { + "PARSEC_CCA.hw-model": "RoadRunner", + "PARSEC_CCA.hw-vendor": "ACME", + "PARSEC_CCA.impl-id": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=", + "PARSEC_CCA.measurement-desc": "sha-256", + "PARSEC_CCA.measurement-type": "BL", + "PARSEC_CCA.measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.version": "3.4.2" + } + }, + { + "scheme": "PARSEC_CCA", + "type": "REFERENCE_VALUE", + "subType": "PARSEC_CCA.sw-component", + "attributes": { + "PARSEC_CCA.hw-model": "RoadRunner", + "PARSEC_CCA.hw-vendor": "ACME", + "PARSEC_CCA.impl-id": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=", + "PARSEC_CCA.measurement-desc": "sha-256", + "PARSEC_CCA.measurement-type": "M1", + "PARSEC_CCA.measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.version": "1.2" + } + }, + { + "scheme": "PARSEC_CCA", + "type": "REFERENCE_VALUE", + "subType": "PARSEC_CCA.sw-component", + "attributes": { + "PARSEC_CCA.hw-model": "RoadRunner", + "PARSEC_CCA.hw-vendor": "ACME", + "PARSEC_CCA.impl-id": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=", + "PARSEC_CCA.measurement-desc": "sha-256", + "PARSEC_CCA.measurement-type": "M2", + "PARSEC_CCA.measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.version": "1.2.3" + } + }, + { + "scheme": "PARSEC_CCA", + "type": "REFERENCE_VALUE", + "subType": "PARSEC_CCA.sw-component", + "attributes": { + "PARSEC_CCA.hw-model": "RoadRunner", + "PARSEC_CCA.hw-vendor": "ACME", + "PARSEC_CCA.impl-id": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=", + "PARSEC_CCA.measurement-desc": "sha-256", + "PARSEC_CCA.measurement-type": "M3", + "PARSEC_CCA.measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "PARSEC_CCA.version": "1" + } + }, + { + "scheme": "PARSEC_CCA", + "type": "REFERENCE_VALUE", + "subType": "PARSEC_CCA.platform-config", + "attributes": { + "PARSEC_CCA.hw-model": "RoadRunner", + "PARSEC_CCA.hw-vendor": "ACME", + "PARSEC_CCA.impl-id": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=", + "PARSEC_CCA.platform-config-label": "platform-config-label", + "PARSEC_CCA.platform-config-id": "AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY" + } + } +] diff --git a/policy/test/inputs/psa-endorsements.json b/policy/test/inputs/psa-endorsements.json index 8596700c..2b268ebe 100644 --- a/policy/test/inputs/psa-endorsements.json +++ b/policy/test/inputs/psa-endorsements.json @@ -1,5 +1,45 @@ [ - "{\n\"scheme\":\"PSA_IOT\",\n\"type\":\"REFERENCE_VALUE\",\n\"attributes\":{\n \"psa.hw-model\":\"RoadRunner\",\n \"psa.hw-vendor\":\"ACME\",\n \"psa.impl-id\":\"76543210fedcba9817161514131211101f1e1d1c1b1a1918\",\n \"psa.measurement-desc\":\"sha-256\",\n \"psa.measurement-type\":\"BL\",\n \"psa.measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"psa.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"psa.version\":\"3.4.2\"\n }\n }", - "\n{\n \"scheme\":\"PSA_IOT\",\n \"type\":\"REFERENCE_VALUE\",\n \"attributes\":{\n \"psa.hw-model\":\"RoadRunner\",\n \"psa.hw-vendor\":\"ACME\",\n \"psa.impl-id\":\"76543210fedcba9817161514131211101f1e1d1c1b1a1918\",\n \"psa.measurement-desc\":\"sha-256\",\n \"psa.measurement-type\":\"M1\",\n \"psa.measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"psa.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"psa.version\":\"1.2.0\"}\n }\n ", - "\n {\n \"scheme\":\"PSA_IOT\",\n \"type\":\"REFERENCE_VALUE\",\n \"attributes\":{\n \"psa.hw-model\":\"RoadRunner\",\n \"psa.hw-vendor\":\"ACME\",\n \"psa.impl-id\":\"76543210fedcba9817161514131211101f1e1d1c1b1a1918\",\n \"psa.measurement-desc\":\"sha-256\",\n \"psa.measurement-type\":\"M2\",\n \"psa.measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"psa.signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"psa.version\":\"1.2.3\"}\n }\n " -] \ No newline at end of file + { + "scheme":"PSA_IOT", + "type":"REFERENCE_VALUE", + "attributes":{ + "psa.hw-model":"RoadRunner", + "psa.hw-vendor":"ACME", + "psa.impl-id":"76543210fedcba9817161514131211101f1e1d1c1b1a1918", + "psa.measurement-desc":"sha-256", + "psa.measurement-type":"BL", + "psa.measurement-value":"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "psa.signer-id":"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "psa.version":"3.4.2" + } + }, + { + "scheme":"PSA_IOT", + "type":"REFERENCE_VALUE", + "attributes":{ + "psa.hw-model":"RoadRunner", + "psa.hw-vendor":"ACME", + "psa.impl-id":"76543210fedcba9817161514131211101f1e1d1c1b1a1918", + "psa.measurement-desc":"sha-256", + "psa.measurement-type":"M1", + "psa.measurement-value":"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "psa.signer-id":"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "psa.version":"1.2.0" + } + }, + { + "scheme":"PSA_IOT", + "type":"REFERENCE_VALUE", + "attributes":{ + "psa.hw-model":"RoadRunner", + "psa.hw-vendor":"ACME", + "psa.impl-id":"76543210fedcba9817161514131211101f1e1d1c1b1a1918", + "psa.measurement-desc":"sha-256", + "psa.measurement-type":"M2", + "psa.measurement-value":"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "psa.signer-id":"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", + "psa.version":"1.2.3" + } + } + +] diff --git a/proto/Makefile b/proto/Makefile index 683aee10..caf76379 100644 --- a/proto/Makefile +++ b/proto/Makefile @@ -10,6 +10,7 @@ PROTOSRCS += state.proto PROTOSRCS += vts.proto PROTOSRCS += status.proto PROTOSRCS += endorsement_query.proto +PROTOSRCS += scheme.proto lint-hook-pre: protogen protolint lint $(PROTOSRCS) diff --git a/proto/appraisal_context.pb.go b/proto/appraisal_context.pb.go index 7b0d39fd..868a0ec7 100644 --- a/proto/appraisal_context.pb.go +++ b/proto/appraisal_context.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: appraisal_context.proto package proto diff --git a/proto/endorsement_query.pb.go b/proto/endorsement_query.pb.go index e327e953..05f76931 100644 --- a/proto/endorsement_query.pb.go +++ b/proto/endorsement_query.pb.go @@ -3,8 +3,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: endorsement_query.proto package proto @@ -30,7 +30,7 @@ type EndorsementQueryIn struct { // media type (including profile) MediaType string `protobuf:"bytes,1,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"` - // base64url-encoded CoSERV + // base64url-encoded CoSERV query Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` } @@ -85,8 +85,9 @@ type EndorsementQueryOut struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - ResultSet []byte `protobuf:"bytes,2,opt,name=result_set,json=resultSet,proto3" json:"result_set,omitempty"` + Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + // CBOR-encoded CoSERV result set + ResultSet []byte `protobuf:"bytes,2,opt,name=result_set,json=resultSet,proto3" json:"result_set,omitempty"` } func (x *EndorsementQueryOut) Reset() { diff --git a/proto/evidence.pb.go b/proto/evidence.pb.go index 20b4bf8e..3ff8b2c1 100644 --- a/proto/evidence.pb.go +++ b/proto/evidence.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: evidence.proto package proto diff --git a/proto/scheme.pb.go b/proto/scheme.pb.go new file mode 100644 index 00000000..894a27c7 --- /dev/null +++ b/proto/scheme.pb.go @@ -0,0 +1,396 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.12 +// source: scheme.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + _ "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetReferenceValueIDsArgs struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TrustAnchors []byte `protobuf:"bytes,1,opt,name=trust_anchors,json=trust-anchors,proto3" json:"trust_anchors,omitempty"` + Claims []byte `protobuf:"bytes,2,opt,name=claims,proto3" json:"claims,omitempty"` +} + +func (x *GetReferenceValueIDsArgs) Reset() { + *x = GetReferenceValueIDsArgs{} + if protoimpl.UnsafeEnabled { + mi := &file_scheme_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetReferenceValueIDsArgs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetReferenceValueIDsArgs) ProtoMessage() {} + +func (x *GetReferenceValueIDsArgs) ProtoReflect() protoreflect.Message { + mi := &file_scheme_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetReferenceValueIDsArgs.ProtoReflect.Descriptor instead. +func (*GetReferenceValueIDsArgs) Descriptor() ([]byte, []int) { + return file_scheme_proto_rawDescGZIP(), []int{0} +} + +func (x *GetReferenceValueIDsArgs) GetTrustAnchors() []byte { + if x != nil { + return x.TrustAnchors + } + return nil +} + +func (x *GetReferenceValueIDsArgs) GetClaims() []byte { + if x != nil { + return x.Claims + } + return nil +} + +type ValidateEvidenceIntegrityArgs struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Evidence *AttestationToken `protobuf:"bytes,1,opt,name=evidence,proto3" json:"evidence,omitempty"` + TrustAnchors []byte `protobuf:"bytes,2,opt,name=trust_anchors,json=trust-anchors,proto3" json:"trust_anchors,omitempty"` + Endorsements []byte `protobuf:"bytes,3,opt,name=endorsements,proto3" json:"endorsements,omitempty"` +} + +func (x *ValidateEvidenceIntegrityArgs) Reset() { + *x = ValidateEvidenceIntegrityArgs{} + if protoimpl.UnsafeEnabled { + mi := &file_scheme_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateEvidenceIntegrityArgs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateEvidenceIntegrityArgs) ProtoMessage() {} + +func (x *ValidateEvidenceIntegrityArgs) ProtoReflect() protoreflect.Message { + mi := &file_scheme_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateEvidenceIntegrityArgs.ProtoReflect.Descriptor instead. +func (*ValidateEvidenceIntegrityArgs) Descriptor() ([]byte, []int) { + return file_scheme_proto_rawDescGZIP(), []int{1} +} + +func (x *ValidateEvidenceIntegrityArgs) GetEvidence() *AttestationToken { + if x != nil { + return x.Evidence + } + return nil +} + +func (x *ValidateEvidenceIntegrityArgs) GetTrustAnchors() []byte { + if x != nil { + return x.TrustAnchors + } + return nil +} + +func (x *ValidateEvidenceIntegrityArgs) GetEndorsements() []byte { + if x != nil { + return x.Endorsements + } + return nil +} + +type ExtractClaimsArgs struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Evidence *AttestationToken `protobuf:"bytes,1,opt,name=evidence,proto3" json:"evidence,omitempty"` + TrustAnchors []byte `protobuf:"bytes,2,opt,name=trust_anchors,json=trust-anchors,proto3" json:"trust_anchors,omitempty"` +} + +func (x *ExtractClaimsArgs) Reset() { + *x = ExtractClaimsArgs{} + if protoimpl.UnsafeEnabled { + mi := &file_scheme_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExtractClaimsArgs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExtractClaimsArgs) ProtoMessage() {} + +func (x *ExtractClaimsArgs) ProtoReflect() protoreflect.Message { + mi := &file_scheme_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExtractClaimsArgs.ProtoReflect.Descriptor instead. +func (*ExtractClaimsArgs) Descriptor() ([]byte, []int) { + return file_scheme_proto_rawDescGZIP(), []int{2} +} + +func (x *ExtractClaimsArgs) GetEvidence() *AttestationToken { + if x != nil { + return x.Evidence + } + return nil +} + +func (x *ExtractClaimsArgs) GetTrustAnchors() []byte { + if x != nil { + return x.TrustAnchors + } + return nil +} + +type AppraiseClaimsArgs struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Claims []byte `protobuf:"bytes,1,opt,name=claims,proto3" json:"claims,omitempty"` + Endorsements []byte `protobuf:"bytes,2,opt,name=endorsements,proto3" json:"endorsements,omitempty"` +} + +func (x *AppraiseClaimsArgs) Reset() { + *x = AppraiseClaimsArgs{} + if protoimpl.UnsafeEnabled { + mi := &file_scheme_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AppraiseClaimsArgs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AppraiseClaimsArgs) ProtoMessage() {} + +func (x *AppraiseClaimsArgs) ProtoReflect() protoreflect.Message { + mi := &file_scheme_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AppraiseClaimsArgs.ProtoReflect.Descriptor instead. +func (*AppraiseClaimsArgs) Descriptor() ([]byte, []int) { + return file_scheme_proto_rawDescGZIP(), []int{3} +} + +func (x *AppraiseClaimsArgs) GetClaims() []byte { + if x != nil { + return x.Claims + } + return nil +} + +func (x *AppraiseClaimsArgs) GetEndorsements() []byte { + if x != nil { + return x.Endorsements + } + return nil +} + +var File_scheme_proto protoreflect.FileDescriptor + +var file_scheme_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x0b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0x58, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x49, 0x44, 0x73, 0x41, 0x72, 0x67, 0x73, 0x12, 0x24, 0x0a, 0x0d, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x61, 0x6e, 0x63, 0x68, 0x6f, + 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x1d, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x45, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x49, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x69, 0x74, 0x79, 0x41, 0x72, 0x67, 0x73, 0x12, 0x33, 0x0a, 0x08, + 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, + 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, + 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2d, + 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x6e, 0x0a, 0x11, 0x45, + 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x41, 0x72, 0x67, 0x73, + 0x12, 0x33, 0x0a, 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x08, 0x65, 0x76, 0x69, + 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x61, + 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2d, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x22, 0x50, 0x0a, 0x12, 0x41, + 0x70, 0x70, 0x72, 0x61, 0x69, 0x73, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x41, 0x72, 0x67, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0c, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x24, 0x5a, + 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x65, 0x72, 0x61, + 0x69, 0x73, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_scheme_proto_rawDescOnce sync.Once + file_scheme_proto_rawDescData = file_scheme_proto_rawDesc +) + +func file_scheme_proto_rawDescGZIP() []byte { + file_scheme_proto_rawDescOnce.Do(func() { + file_scheme_proto_rawDescData = protoimpl.X.CompressGZIP(file_scheme_proto_rawDescData) + }) + return file_scheme_proto_rawDescData +} + +var file_scheme_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_scheme_proto_goTypes = []interface{}{ + (*GetReferenceValueIDsArgs)(nil), // 0: proto.GetReferenceValueIDsArgs + (*ValidateEvidenceIntegrityArgs)(nil), // 1: proto.ValidateEvidenceIntegrityArgs + (*ExtractClaimsArgs)(nil), // 2: proto.ExtractClaimsArgs + (*AppraiseClaimsArgs)(nil), // 3: proto.AppraiseClaimsArgs + (*AttestationToken)(nil), // 4: proto.AttestationToken +} +var file_scheme_proto_depIdxs = []int32{ + 4, // 0: proto.ValidateEvidenceIntegrityArgs.evidence:type_name -> proto.AttestationToken + 4, // 1: proto.ExtractClaimsArgs.evidence:type_name -> proto.AttestationToken + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_scheme_proto_init() } +func file_scheme_proto_init() { + if File_scheme_proto != nil { + return + } + file_token_proto_init() + if !protoimpl.UnsafeEnabled { + file_scheme_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetReferenceValueIDsArgs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_scheme_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateEvidenceIntegrityArgs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_scheme_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExtractClaimsArgs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_scheme_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AppraiseClaimsArgs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_scheme_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_scheme_proto_goTypes, + DependencyIndexes: file_scheme_proto_depIdxs, + MessageInfos: file_scheme_proto_msgTypes, + }.Build() + File_scheme_proto = out.File + file_scheme_proto_rawDesc = nil + file_scheme_proto_goTypes = nil + file_scheme_proto_depIdxs = nil +} diff --git a/proto/scheme.pb.json.go b/proto/scheme.pb.json.go new file mode 100644 index 00000000..2b70f0f3 --- /dev/null +++ b/proto/scheme.pb.json.go @@ -0,0 +1,72 @@ +// Code generated by protoc-gen-go-json. DO NOT EDIT. +// source: scheme.proto + +package proto + +import ( + "google.golang.org/protobuf/encoding/protojson" +) + +// MarshalJSON implements json.Marshaler +func (msg *GetReferenceValueIDsArgs) MarshalJSON() ([]byte, error) { + return protojson.MarshalOptions{ + UseEnumNumbers: false, + EmitUnpopulated: false, + UseProtoNames: false, + }.Marshal(msg) +} + +// UnmarshalJSON implements json.Unmarshaler +func (msg *GetReferenceValueIDsArgs) UnmarshalJSON(b []byte) error { + return protojson.UnmarshalOptions{ + DiscardUnknown: false, + }.Unmarshal(b, msg) +} + +// MarshalJSON implements json.Marshaler +func (msg *ValidateEvidenceIntegrityArgs) MarshalJSON() ([]byte, error) { + return protojson.MarshalOptions{ + UseEnumNumbers: false, + EmitUnpopulated: false, + UseProtoNames: false, + }.Marshal(msg) +} + +// UnmarshalJSON implements json.Unmarshaler +func (msg *ValidateEvidenceIntegrityArgs) UnmarshalJSON(b []byte) error { + return protojson.UnmarshalOptions{ + DiscardUnknown: false, + }.Unmarshal(b, msg) +} + +// MarshalJSON implements json.Marshaler +func (msg *ExtractClaimsArgs) MarshalJSON() ([]byte, error) { + return protojson.MarshalOptions{ + UseEnumNumbers: false, + EmitUnpopulated: false, + UseProtoNames: false, + }.Marshal(msg) +} + +// UnmarshalJSON implements json.Unmarshaler +func (msg *ExtractClaimsArgs) UnmarshalJSON(b []byte) error { + return protojson.UnmarshalOptions{ + DiscardUnknown: false, + }.Unmarshal(b, msg) +} + +// MarshalJSON implements json.Marshaler +func (msg *AppraiseClaimsArgs) MarshalJSON() ([]byte, error) { + return protojson.MarshalOptions{ + UseEnumNumbers: false, + EmitUnpopulated: false, + UseProtoNames: false, + }.Marshal(msg) +} + +// UnmarshalJSON implements json.Unmarshaler +func (msg *AppraiseClaimsArgs) UnmarshalJSON(b []byte) error { + return protojson.UnmarshalOptions{ + DiscardUnknown: false, + }.Unmarshal(b, msg) +} diff --git a/proto/scheme.proto b/proto/scheme.proto new file mode 100644 index 00000000..0b32fdd2 --- /dev/null +++ b/proto/scheme.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; +package proto; + +import "google/protobuf/struct.proto"; +import "token.proto"; + +option go_package = "github.com/veraison/services/proto"; + +message GetReferenceValueIDsArgs { + bytes trust_anchors = 1 [json_name = "trust-anchors"]; + bytes claims = 2 [json_name = "claims"]; +} + +message ValidateEvidenceIntegrityArgs { + AttestationToken evidence = 1 [json_name = "evidence"]; + bytes trust_anchors = 2 [json_name = "trust-anchors"]; + bytes endorsements = 3 [json_name = "endorsements"]; +} + +message ExtractClaimsArgs { + AttestationToken evidence = 1 [json_name = "evidence"]; + bytes trust_anchors = 2 [json_name = "trust-anchors"]; +} + +message AppraiseClaimsArgs { + bytes claims = 1 [json_name = "claims"]; + bytes endorsements = 2 [json_name = "endorsements"]; +} diff --git a/proto/state.pb.go b/proto/state.pb.go index 124d9d72..af9535fa 100644 --- a/proto/state.pb.go +++ b/proto/state.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: state.proto package proto diff --git a/proto/status.pb.go b/proto/status.pb.go index 3f71b220..d4a3ed3f 100644 --- a/proto/status.pb.go +++ b/proto/status.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: status.proto package proto diff --git a/proto/token.pb.go b/proto/token.pb.go index c82e5d49..e814a950 100644 --- a/proto/token.pb.go +++ b/proto/token.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: token.proto package proto diff --git a/proto/vts.pb.go b/proto/vts.pb.go index 35ec2bef..5bdb0b19 100644 --- a/proto/vts.pb.go +++ b/proto/vts.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc-gen-go v1.26.0 +// protoc v3.21.12 // source: vts.proto package proto diff --git a/proto/vts_grpc.pb.go b/proto/vts_grpc.pb.go index 729c8645..d780f25a 100644 --- a/proto/vts_grpc.pb.go +++ b/proto/vts_grpc.pb.go @@ -1,8 +1,4 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v5.29.3 -// source: vts.proto package proto diff --git a/provisioning/api/router.go b/provisioning/api/router.go index 24a665da..59673abd 100644 --- a/provisioning/api/router.go +++ b/provisioning/api/router.go @@ -1,4 +1,4 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package api @@ -12,7 +12,7 @@ import ( var publicApiMap = make(map[string]string) const ( - provisioningPath = "/endorsement-provisioning/v1" + provisioningPath = "/endorsement-provisioning/v1" getWellKnownProvisioningInfoPath = "/.well-known/veraison/provisioning" ) @@ -30,6 +30,5 @@ func NewRouter(handler IHandler, authorizer auth.IAuthorizer) *gin.Engine { provGroup.POST("submit", handler.Submit) publicApiMap["provisioningSubmit"] = path.Join(provisioningPath, "submit") - return router } diff --git a/provisioning/cmd/provisioning-service/main.go b/provisioning/cmd/provisioning-service/main.go index e99cfe0f..62398390 100644 --- a/provisioning/cmd/provisioning-service/main.go +++ b/provisioning/cmd/provisioning-service/main.go @@ -1,4 +1,4 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -49,7 +49,7 @@ func main() { cfg := cfg{ ListenAddr: DefaultListenAddr, - Protocol: "https", + Protocol: "https", } subs, err := config.GetSubs(v, "provisioning", "vts", "*logging", "*auth") diff --git a/provisioning/test-harness/req.sh b/provisioning/test-harness/req.sh index 7fb50d4e..a0be5d6b 100755 --- a/provisioning/test-harness/req.sh +++ b/provisioning/test-harness/req.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2022-2023 Contributors to the Veraison project. +# Copyright 2022-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 set -o pipefail diff --git a/scheme/MIGRATING.md b/scheme/MIGRATING.md deleted file mode 100644 index eee83cd9..00000000 --- a/scheme/MIGRATING.md +++ /dev/null @@ -1,95 +0,0 @@ -This is a guide for converting plugins written for an earlier version of -Veraison to the updated plugin framework. - -1. Remove `GetFormat()`. Attestation formats are no longer required -- the - combination of the plugin scheme (see (3) below) and media types is now used - to select plugins. -2. Update `GetName()`. If this was previously implemented in terms of the - format. This can now be defined as a string constant. -3. Add `GetAttestationScheme()` method. This should return a `string` naming - the attestation scheme you're implementing. - - > **Warning**: it is important that both `IEndorsementHandler` and - > `IEvidinceHandler` implementations for a scheme return the same values for - > this -- it is the connection that allows the verification flow to - > correctly identify relevant endorsements provisioned via the provisioning - > flow. - -4. Replace `main()`. Instead of using HashiCorp APIs directly, Veraison now - provides a couple of methods to handle plugin creation. - - Instead of some thing like - - ```go - package main - - import "github.com/hashicorp/go-plugin" - - type Scheme struct {} - - // ... - // Scheme implementation goes here - // ... - - func main() { - var handshakeConfig = plugin.HandshakeConfig{ - ProtocolVersion: 1, - MagicCookieKey: "VERAISON_PLUGIN", - MagicCookieValue: "VERAISON", - } - - var pluginMap = map[string]plugin.Plugin{ - "scheme": &scheme.Plugin{ - Impl: &Scheme{}, - }, - } - - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: handshakeConfig, - Plugins: pluginMap, - }) - } - ``` - - You now need to do: - - ```go - package main - - import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - ) - - type Scheme struct {} - - // ... - // Scheme implementation goes here - // ... - - func main() { - handler.RegisterEvidenceHandler(&Scheme{}) - // note the change to the import of "plugin" above - plugin.Serve() - } - ``` - -The above example is for the verification-side "scheme" plugins (note: these -are now known as "evidence handlers" within Veraison code base, but the only -API change is the removal of `GetFormat()` mentioned above. - -Identical changes would also need to be made to the provisioning-side "handler" -plugins (now known as "endorsement handlers" within Veraison code base), with -the only difference that `handler.RegisterEndorsementwHandler()` should be used -instead inside `main()`. - -It is now also possible to build both plugins into a single binary, simply by -registering both implementations: - -```go -func main() { - handler.RegisterEvidenceHandler(&Scheme{}) - handler.RegisterEndorsementHandler(&Decoder{}) - plugin.Serve() -} -``` diff --git a/scheme/Makefile b/scheme/Makefile index 9ebb1207..6791ac56 100644 --- a/scheme/Makefile +++ b/scheme/Makefile @@ -1,16 +1,18 @@ -# Copyright 2021-2022 Contributors to the Veraison project. +# Copyright 2021-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -SUBDIR := common +SUBDIR += common + SUBDIR += arm-cca -SUBDIR += riot +SUBDIR += parsec-cca +SUBDIR += parsec-tpm SUBDIR += psa-iot +SUBDIR += riot +SUBDIR += sevsnp SUBDIR += tpm-enacttrust -SUBDIR += parsec-tpm -SUBDIR += parsec-cca -SUBDIR += nvidia-coserv + SUBDIR += amd-kds-coserv -SUBDIR += sevsnp +SUBDIR += nvidia-coserv clean: ; $(RM) -rf ./bin diff --git a/scheme/README.md b/scheme/README.md index 5bed35d1..75e56d75 100644 --- a/scheme/README.md +++ b/scheme/README.md @@ -23,65 +23,223 @@ Currently the following schemes are implemented: ## Implementing Attestation Scheme Support > [!NOTE] -> If you already have attestation scheme plugins implemented for an -> earlier version of Veraison, please see the [migration guide](MIGRATING.md) -> for how to convert them to the new framework. - -Supporting a new attestation scheme requires defining how to provision -endorsements (if any) by implementing -[`IEndorsementHandler`](../handler/iendorsementhandler.go), how to process -evidence tokens by implementing -[`IEvidenceHandler`](../handler/ievidencehandler.go), how to create and obtain -scheme-specific keys used to store and retrieve endorsements and trust anchors -by implementing [`IStoreHandler`](../handler/istorehandler.go), and how to -handle CoSERV queries by implementing -[`ICoservProxyHandler`](../handler/icoservproxyhandler.go). - -Finally, an executable should be created that [registers](../handler/plugin.go) -and serves them. +> `example` sub-directory contains a "template" for new scheme boiler plate. +> You can start implementing a new scheme by copying it and filling in the +> TODO's. + +An implementation of an attestation scheme needs to provide two things: + +- A [`SchemeDescriptor`](../handler/schemedescriptor.go) providing basic + information about the scheme. +- An implementation of + [`ISchemeImplementation`](../handler/ischemeimplementation.go) interface. + +Both of these need to then be registered + +- as a plugin by calling `handler.RegisterSchemeImpalementation`, and +- for in-line implementations (i.e. those that are part of this code base), by + updating [builtin/schemes.go](../builtin/schemes.go) + ```go package main import ( - "github.com/veraison/services/decoder" + "github.com/veraison/services/handler" "github.com/veraison/services/plugin" ) -type MyEvidenceHandler struct {} +var Descriptor = handler.SchemeDescriptor{ + Name: "MY_SCHEME", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + "http://my-org/my-scheme", + }, + EvidenceMediaTypes: []string{ + "application/my-scheme-evidence", + }, +} + +type Implementation struct {} // ... -// Implementation of IEvidenceHandler for MyEvidenceHandler +// Implementation of ISchemeImplementation for Implementation // ... -type MyEndrosementHandler struct {} +func main() { + handler.RegisterSchemeImplementation(Descriptor, &Implementation{}) + plugin.Serve() +} +``` -// ... -// Implementation of IEndrosementHandler for MyEndrosementHandler -// ... +### Validating endorsements and trust anchors -type MyStoreHandler struct {} +Endorsements and trust anchors are provisioned as CoRIMs into the store using +a standard provisioning flow. A scheme implementation does not need to worry +about that except to make sure that the CoRIM provisioned for it contains the +information it expects. -// ... -// Implementation of IStoreHandler for MyStoreHandler -// ... +The recommended way to do that is to utilize the validation support provided by +the CoRIM libraries [profile extensions +mechanism](https://github.com/veraison/corim/blob/main/extensions/README.md). + +```go +type TriplesValidator struct {} -type MyCoservProxyHandler struct {} +func (o *TriplesValidator) ValidTriples(triples *comid.Triples) error { + // make sure the triples contain the right data for the scheme, returning + // an error if they don't. + + return nil +} + +func init() { + extMap := extensions.NewMap().Add(comid.ExtTriples, &TriplesValidator{}) + + for _, profileString := range Descriptor.CorimProfiles { + profileID, err := eat.NewProfile(profileString) + if err != nil { + panic(err) + } + + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } + } +} + +``` + +To make this easier, we provide standard `TriplesValidator` implementation that +only needs to be given callback validators for individual elements (such as +environments). E.g. + +```go +import ( + "github.com/veraison/corim/comid" + "github.com/veraison/services/scheme/common" +) + +func revValEnvValidator(e *comid.Environment) error { + // validate reference value environment + return nil +} + +func taEnvValidator(e *comid.Environment) error { + // validate trust anchor environment + return nil +} + +func measurementsValidator(meas []comid.Measurement) error { + // validate reference value measurements environment + return nil +} + +func cryptoKeysValidator(keys []*comid.CryptoKeys) error { + // validate attestation verification keys + return nil +} + +var validator = &common.TriplesValidator{ + TAEnviromentValidator: taEnvValidator, + RefValEnviromentValidator: refValEnvValidator, + // Alternatively to the above, EnvironmentValidator may specified, which + // will be invoked for both trust anchors and reference values. + CryptoKeysValidator: measurementsValidator, + MeasurementsValidator: cryptoKeysValidator, +} + +func init() { + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + + // ... +} +``` +Yo do not need to specify all the validator functions listed above -- just the +ones for the elements you care about for your scheme. + +### `ISchemeHander` + +VTS actually expects [`ISchemeHander`](../handler/ischemehandler.go) to be +implemented by plugins. [A wrapper](../handler/schemeimplementationwrapper.go) +provides this based on the `SchemeDescriptor` and `ISchemeImplementation`. This +results in a simpler, more declarative scheme definition. + +In general, it is recommended that new schemes are defined using +`SchemeDescriptor` and `ISchemeImplementation` as described above. If, for +whatever reason, this is not sufficient, it is possible to implement +`ISchemeHandler` directly: + +```go +package main + +import ( + "github.com/veraison/services/handler" + "github.com/veraison/services/plugin" +) + +type Handler struct {} // ... -// Implementation of ICoservProxyHandler for MyCoservProxyHandler +// Implementation of ISchemeHandler for Handler // ... func main() { - handler.RegisterEndorsementHandler(&MyEndorsementHandler{}) - handler.RegisterEvidenceHandler(&MyEvidenceHandler{}) - handler.RegisterStoreHandler(&MyStoreHandler{}) - handler.RegisterCoservProxyHandler(&MyCoservProxyHandler{}) - + handler.RegisterSchemeHandler(&Handler{}) plugin.Serve() } ``` +(Note that `ISchemeHandler` embeds `ISchemeImplementation`, so you would still +need to implement it.) + +## Guidance on structuring and using CoRIMs in attestation schemes + +> [!NOTE] +> This section should viewed as supplementing section 5.1 of +> [draft-ietf-rats-corim-09]. It describes how the CoRIMs are used by the +> Veraison Trusted Services (VTS) and therefore how they may be used by +> attestation schemes. + +VTS deals with endorsements (reference measurements) and trust anchors as basic +units of provisioned data. This maps directly to `reference-triples` and +`attest-key-triples` described in section 5.1.4 of [draft-ietf-rats-corim-09]. + +Triples relevant to a particular attestation are identified based on their +environments by matching them to the environments generated from the +attestation evidence during verification flow. + +Keep in mind the following things when structuring CoRIMs for use with Veraison +Services: + +- CoRIMs must contain _only_ CoMID tags; no other tags are supported. A CoRIM + may contain any number of CoMIDs. +- Any information relevant to attestation verification must be contained + _solely_ within `reference-triples` and `attest-key-triples` + (`Triples.ReferenceValues` and `Triples.AttestVerifKeys` in the Go package) + [^1]. A CoMID may contain any number of these triples. +- Meaning must NOT be assigned to the grouping of triples within a CoMID, or + grouping of CoMIDs within a CoRIM. This grouping information is not available + to the attestation schemes -- all relevant triples are retrieved as a single + list. +- Meaning CAN be assigned to grouping of measurements within a single reference + value triple, or to the grouping of keys within a single attest. verif. key + triple. +- Any information needed to match a triple to evidence must be contained + _solely_ in the triple's environment; and the environments must _only_ + contain information needed to match a triple to evidence. + +Aside from the above constraints, the format of CoRIMs/CoMIDs is left up to the +individual attestation schemes. + +[^1]: The CoRIM store used by VTS can also accommodate `identity-triples` and + `endorsed-triples`, however these will never be retrieved for verification. + The store does not currently support any other triple type and will return + an error when trying to add them. + +[draft-ietf-rats-corim-09]: https://datatracker.ietf.org/doc/draft-ietf-rats-corim/ + ## Debugging Handler code is a lot easier to debug when it runs as part of the service diff --git a/scheme/amd-kds-coserv/coserv_handler.go b/scheme/amd-kds-coserv/coserv_handler.go index 73db4f97..5a2e341c 100644 --- a/scheme/amd-kds-coserv/coserv_handler.go +++ b/scheme/amd-kds-coserv/coserv_handler.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package amdkdscoserv @@ -57,8 +57,8 @@ func (s CoservProxyHandler) GetAttestationScheme() string { return SchemeName } -func (s CoservProxyHandler) GetSupportedMediaTypes() []string { - return CoservMediaTypes +func (s CoservProxyHandler) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{"coserv": CoservMediaTypes} } func (s CoservProxyHandler) addTrustAnchorForInstance(i *coserv.StatefulInstance, results *coserv.ResultSet) error { diff --git a/scheme/amd-kds-coserv/plugin/Makefile b/scheme/amd-kds-coserv/plugin/Makefile index 730c6798..ea0015f6 100644 --- a/scheme/amd-kds-coserv/plugin/Makefile +++ b/scheme/amd-kds-coserv/plugin/Makefile @@ -1,8 +1,11 @@ -ifndef COMBINED_PLUGINS - SUBDIR += coserv-handler -else - SUBDIR += combined -endif +# Copyright 2025 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +PLUGIN := ../../bin/coserv-amd-kds.plugin +GOPKG := github.com/veraison/services/scheme/amd-kds-coserv +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/amd-kds-coserv/plugin/combined/Makefile b/scheme/amd-kds-coserv/plugin/combined/Makefile deleted file mode 100644 index f60402e6..00000000 --- a/scheme/amd-kds-coserv/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/amd-kds-coserv.plugin -GOPKG := github.com/veraison/services/scheme/amd-kds-coserv -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/amd-kds-coserv/plugin/combined/main.go b/scheme/amd-kds-coserv/plugin/combined/main.go deleted file mode 100644 index 236c7405..00000000 --- a/scheme/amd-kds-coserv/plugin/combined/main.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/amd-kds-coserv" -) - -func main() { - handler.RegisterCoservProxyHandler(&scheme.CoservProxyHandler{}) - plugin.Serve() -} diff --git a/scheme/amd-kds-coserv/plugin/coserv-handler/Makefile b/scheme/amd-kds-coserv/plugin/coserv-handler/Makefile deleted file mode 100644 index f60402e6..00000000 --- a/scheme/amd-kds-coserv/plugin/coserv-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/amd-kds-coserv.plugin -GOPKG := github.com/veraison/services/scheme/amd-kds-coserv -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/amd-kds-coserv/plugin/coserv-handler/main.go b/scheme/amd-kds-coserv/plugin/main.go similarity index 83% rename from scheme/amd-kds-coserv/plugin/coserv-handler/main.go rename to scheme/amd-kds-coserv/plugin/main.go index 236c7405..5f0bd720 100644 --- a/scheme/amd-kds-coserv/plugin/coserv-handler/main.go +++ b/scheme/amd-kds-coserv/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main diff --git a/scheme/arm-cca/Makefile b/scheme/arm-cca/Makefile index 5e974738..46a954f9 100644 --- a/scheme/arm-cca/Makefile +++ b/scheme/arm-cca/Makefile @@ -1,4 +1,4 @@ -# Copyright 2022-2024 Contributors to the Veraison project. +# Copyright 2021 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 .DEFAULT_GOAL := test diff --git a/scheme/arm-cca/README.md b/scheme/arm-cca/README.md deleted file mode 100644 index 4b59035e..00000000 --- a/scheme/arm-cca/README.md +++ /dev/null @@ -1,84 +0,0 @@ -This directory contains packages implementing `arm-cca` (Arm Confidential Compute Architecture) attestation scheme. - -Arm CCA attestation scheme is a composite attestation scheme which comprises a CCA Platform Attestation & a Realm Attestation. - -Endorsement Store Interface for the CCA Platform and Realm Attestation Scheme is given below. - -## Endorsement Store Interface - -### Arm CCA Platform - -#### Reference Value -```json -{ - "scheme": "ARM_CCA", - "type": "reference value", - "subType": "platform.sw-component", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "measurement-desc": "sha-256", - "measurement-type": "BL", - "measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "version": "3.4.2" - } -} -{ - "scheme": "ARM_CCA", - "type": "reference value", - "subType": "platform.config", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "platform-config-id": "AQID", - "platform-config-label": "cfg v1.0.0" - } -} -``` - -#### Trust Anchor -```json -{ - "scheme": "ARM_CCA", - "type": "trust anchor", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "impl-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "inst-id": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" - } -} -``` - -### Arm CCA Realm - -#### Reference Value - -A Realm instance is uniquely identified by the values of Realm initial measurements and Realm Personalization Value (if provided) used to launch a Realm. - -```json -{ - "scheme": "ARM_CCA", - "type": "REFERENCE_VALUE", - "subType": "realm.reference-value", - "attributes": { - "vendor": "Workload Client Ltd", - "class-id": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C", - "realm-initial-measurement": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1", - "hash-alg-id": "sha-384", - "realm-personalization-value": "5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82j/dOYjR6gk3stnqE5SJNdQ==", - "rem0": "IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4", - "rem1": "JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4", - "rem2": "MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4", - "rem3": "NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - } -} -``` - -#### Trust Anchor - -Realms have no explicit Trust Anchor to provision, as they are supplied inline in the Realm attestation token. diff --git a/scheme/arm-cca/corim.go b/scheme/arm-cca/corim.go new file mode 100644 index 00000000..0579d0ca --- /dev/null +++ b/scheme/arm-cca/corim.go @@ -0,0 +1,169 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package arm_cca + +import ( + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/services/scheme/common" +) + +const ( + LegacyPlatformProfileString = "http://arm.com/cca/ssd/1" + LegacyRealmProfileString = "http://arm.com/cca/realm/1" + PlatformProfileString = "tag:arm.com,2023:cca_platform#1.0.0" + RealmProfileString = "tag:arm.com,2023:realm#1.0.0" +) + +func ValidatePlatformEnvironment(env *comid.Environment, isTrustAnchor bool) error { + if env.Class == nil { + return errors.New("class not set") + } + + if env.Class.ClassID == nil { + return errors.New("class ID not set") + } + + if env.Class.ClassID.Type() != comid.ImplIDType { + return fmt.Errorf("class ID: expected psa.impl-id, got %s", env.Class.ClassID.Type()) + } + + if isTrustAnchor { + if env.Instance == nil { + return errors.New("instance not set for trust anchor") + } + + if env.Instance.Type() != comid.UEIDType { + return fmt.Errorf("instance: expected UEID, got %s", env.Instance.Type()) + } + + } else if env.Instance != nil { + return errors.New("instance set for reference value") + } + + return nil +} + +func validateRealmEnvironment(env *comid.Environment) error { + if env.Instance == nil { + return errors.New("instance not set") + } + + if env.Instance.Type() != comid.BytesType { + return fmt.Errorf("instance: expected bytes, got %s", env.Instance.Type()) + } + + return nil +} + +func ValidateCryptoKeys(keys []*comid.CryptoKey) error { + if len(keys) != 1 { + return fmt.Errorf("expected exactly one key but got %d", len(keys)) + } + + if keys[0].Type() != comid.PKIXBase64KeyType { + return fmt.Errorf("trust anchor must be a PKIX base64 key, found: %s", keys[0].Type()) + } + + return nil +} + +func ValidatePlatformMeasurements(measurements []comid.Measurement) error { + for i, mea := range measurements { + if mea.Key == nil { + return fmt.Errorf("measurement %d key not set", i) + } + + switch mea.Key.Type() { + case comid.PSARefValIDType: + if mea.Val.Digests == nil { + return fmt.Errorf("measurement %d value: no digests", i) + } + case comid.CCAPlatformConfigIDType: + if mea.Val.RawValue == nil { + return fmt.Errorf("measurement %d value: no raw value", i) + } + default: + return fmt.Errorf("measurement %d key: unexpected type %s", i, mea.Key.Type()) + } + + } + + return nil +} + +func validateRealmMeasurements(measurements []comid.Measurement) error { + for i, mea := range measurements { + if mea.Val.RawValue == nil { + return fmt.Errorf("measurement %d: personalization (raw value) not set", i) + } + + if mea.Val.IntegrityRegisters == nil { + return fmt.Errorf("measurement %d integrity registers not set", i) + } + } + + return nil +} + +func init() { + platformProfileID, err := eat.NewProfile(PlatformProfileString) + if err != nil { + panic(err) + } + + legacyPlatformProfileID, err := eat.NewProfile(LegacyPlatformProfileString) + if err != nil { + panic(err) + } + + realmProfileID, err := eat.NewProfile(RealmProfileString) + if err != nil { + panic(err) + } + + legacyRealmProfileID, err := eat.NewProfile(LegacyRealmProfileString) + if err != nil { + panic(err) + } + + platformValidator := &common.TriplesValidator{ + TAEnviromentValidator: func(e *comid.Environment) error { + return ValidatePlatformEnvironment(e, true) + }, + RefValEnviromentValidator: func(e *comid.Environment) error { + return ValidatePlatformEnvironment(e, false) + }, + CryptoKeysValidator: ValidateCryptoKeys, + MeasurementsValidator: ValidatePlatformMeasurements, + } + platformExtMap := extensions.NewMap().Add(comid.ExtTriples, platformValidator) + + realmValidator := &common.TriplesValidator{ + EnviromentValidator: validateRealmEnvironment, + MeasurementsValidator: validateRealmMeasurements, + DisallowTAs: true, + } + realmExtMap := extensions.NewMap().Add(comid.ExtTriples, realmValidator) + + if err := corim.RegisterProfile(platformProfileID, platformExtMap); err != nil { + panic(err) + } + + if err := corim.RegisterProfile(legacyPlatformProfileID, platformExtMap); err != nil { + panic(err) + } + + if err := corim.RegisterProfile(realmProfileID, realmExtMap); err != nil { + panic(err) + } + + if err := corim.RegisterProfile(legacyRealmProfileID, realmExtMap); err != nil { + panic(err) + } +} diff --git a/scheme/arm-cca/corim_extractor.go b/scheme/arm-cca/corim_extractor.go deleted file mode 100644 index 3b40f875..00000000 --- a/scheme/arm-cca/corim_extractor.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package arm_cca - -import ( - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common/cca/platform" - "github.com/veraison/services/scheme/common/cca/realm" -) - -type CorimExtractor struct { - Profile string -} - -func (o CorimExtractor) RefValExtractor(rvs comid.ValueTriples) ([]*handler.Endorsement, error) { - switch o.Profile { - case "http://arm.com/cca/ssd/1": - subScheme := &platform.CcaSsdExtractor{Scheme: SchemeName} - return subScheme.RefValExtractor(rvs) - case "http://arm.com/cca/realm/1": - subScheme := &realm.RealmExtractor{Scheme: SchemeName} - return subScheme.RefValExtractor(rvs) - default: - return nil, fmt.Errorf("invalid profile %s for scheme %s", o.Profile, SchemeName) - } -} - -func (o CorimExtractor) TaExtractor(avk comid.KeyTriple) (*handler.Endorsement, error) { - switch o.Profile { - case "http://arm.com/cca/ssd/1": - subScheme := &platform.CcaSsdExtractor{Scheme: SchemeName} - return subScheme.TaExtractor(avk) - default: - return nil, fmt.Errorf("invalid profile%s for scheme %s", o.Profile, SchemeName) - } -} - -func (o *CorimExtractor) SetProfile(profile string) { - o.Profile = profile -} diff --git a/scheme/arm-cca/corim_test.go b/scheme/arm-cca/corim_test.go new file mode 100644 index 00000000..cfbd2dc2 --- /dev/null +++ b/scheme/arm-cca/corim_test.go @@ -0,0 +1,89 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package arm_cca + +import ( + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "platform ok", + Input: corimCcaPlatformValid, + }, + { + Title: "platform bad no class", + Input: corimCcaPlatformBadNoClass, + Err: "class not set", + }, + { + Title: "platform bad TA no instance", + Input: corimCcaPlatformBadTaNoInstance, + Err: "instance not set for trust anchor", + }, + { + Title: "platform bad TA bytes instance", + Input: corimCcaPlatformBadTaInstance, + Err: "instance: expected UEID, got bytes", + }, + { + Title: "platform bad TA cert", + Input: corimCcaPlatformBadTaCert, + Err: "trust anchor must be a PKIX base64 key, found: pkix-base64-cert", + }, + { + Title: "platform bad RefVal instance", + Input: corimCcaPlatformBadRefvalInstance, + Err: "instance set for reference value", + }, + { + Title: "platform bad RefVal no mkey", + Input: corimCcaPlatformBadRefvalNoMkey, + Err: "measurement 0 key not set", + }, + { + Title: "platform bad RefVal uint mkey", + Input: corimCcaPlatformBadRefvalMkey, + Err: "measurement 0 key: unexpected type uint", + }, + { + Title: "platform bad RefVal no digest", + Input: corimCcaPlatformBadRefvalNoDigests, + Err: "measurement 0 value: no digests", + }, + { + Title: "platform bad RefVal no raw value", + Input: corimCcaPlatformBadRefvalNoRawValue, + Err: "measurement 0 value: no raw value", + }, + { + Title: "realm ok", + Input: corimCcaRealmValid, + }, + { + Title: "realm bad instance", + Input: corimCcaRealmBadInstance, + Err: "instance: expected bytes, got ueid", + }, + { + Title: "realm bad no instance", + Input: corimCcaRealmBadNoInstance, + Err: "instance not set", + }, + { + Title: "realm bad no integ. registers", + Input: corimCcaRealmBadNoIntegRegs, + Err: "integrity registers not set", + }, + { + Title: "realm bad no raw value", + Input: corimCcaRealmBadNoRawValue, + Err: "personalization (raw value) not set", + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/arm-cca/endorsement_handler.go b/scheme/arm-cca/endorsement_handler.go deleted file mode 100644 index 2e2a76f7..00000000 --- a/scheme/arm-cca/endorsement_handler.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package arm_cca - -import ( - "encoding/json" - "fmt" - "time" - - "mime" - - "github.com/veraison/corim/comid" - "github.com/veraison/corim/coserv" - - "github.com/veraison/services/handler" - "github.com/veraison/services/log" - "github.com/veraison/services/scheme/common" - "github.com/veraison/services/scheme/common/arm" -) - -type EndorsementHandler struct{} - -func (o EndorsementHandler) Init(params handler.EndorsementHandlerParams) error { - return nil // no-op -} - -func (o EndorsementHandler) Close() error { - return nil // no-op -} - -func (o EndorsementHandler) GetName() string { - return "corim (CCA platform profile)" -} - -func (o EndorsementHandler) GetAttestationScheme() string { - return SchemeName -} - -func (o EndorsementHandler) GetSupportedMediaTypes() []string { - return EndorsementMediaTypes -} - -func (o EndorsementHandler) Decode(data []byte, mediaType string, caCertPool []byte) (*handler.EndorsementHandlerResponse, error) { - extractor := &CorimExtractor{} - - if mediaType != "" { - mt, _, err := mime.ParseMediaType(mediaType) - if err != nil { - return nil, err - } - - // Use signed decoder for signed CoRIM - if mt == "application/rim+cose" { - return common.SignedCorimDecoder(data, extractor, caCertPool) - } - } - - // Default to unsigned CoRIM decoder - return common.UnsignedCorimDecoder(data, extractor) -} - -func (o EndorsementHandler) CoservRepackage(query string, resultSet []string) ([]byte, error) { - var q coserv.Coserv - if err := q.FromBase64Url(query); err != nil { - return nil, err - } - - // add (dummy, for now) authority - authority, err := comid.NewCryptoKeyTaggedBytes([]byte("dummyauth")) - if err != nil { - return nil, fmt.Errorf("unable to map (dummy) authority: %w", err) - } - - // add (dummy, for now) expiry - dummyExpiry := time.Now().Add(time.Hour * 1) - - rset := coserv.NewResultSet() - rset.SetExpiry(dummyExpiry) - - log.Debugf("result set: %v", resultSet) - - for i, j := range resultSet { - var e handler.Endorsement - err := json.Unmarshal([]byte(j), &e) - if err != nil { - return nil, fmt.Errorf("unable to decode result[%d] %q to Endorsement: %w", i, j, err) - } - - switch q.Query.ArtifactType { - // reference values - case coserv.ArtifactTypeReferenceValues: - if e.Type != "reference value" { - log.Errorf("CCA query-result mismatch: want reference value, got %s", e.Type) - continue - } else if e.SubType != "platform.sw-component" { - log.Warnf("CCA reference values of sub-type %q are not currently handled", e.SubType) - continue - } - - rvt, err := arm.EndorsementToReferenceValueTriple(e) - if err != nil { - return nil, fmt.Errorf("unable to map result[%d] %q to CoRIM reference value triple: %w", i, j, err) - } - - rvq := &coserv.RefValQuad{ - Authorities: comid.NewCryptoKeys().Add(authority), - RVTriple: rvt, - } - - rset.AddReferenceValues(*rvq) - - // trust anchors - case coserv.ArtifactTypeTrustAnchors: - if e.Type != "trust anchor" { - log.Errorf("CCA query-result mismatch: want trust anchor, got %s", e.Type) - continue - } - - akt, err := arm.EndorsementToAttestationKeyTriple(e) - if err != nil { - return nil, fmt.Errorf("unable to map result[%d] %q to CoRIM attest key triple: %w", i, j, err) - } - - akq := &coserv.AKQuad{ - Authorities: comid.NewCryptoKeys().Add(authority), - AKTriple: akt, - } - - rset.AddAttestationKeys(*akq) - - default: - log.Errorf("CCA CoSERV can only deal with reference values and trust anchors at the moment") - continue - } - } - - if err := q.AddResults(*rset); err != nil { - return nil, fmt.Errorf("failure adding the translated result set: %w", err) - } - - return q.ToCBOR() -} diff --git a/scheme/arm-cca/endorsement_handler_test.go b/scheme/arm-cca/endorsement_handler_test.go deleted file mode 100644 index 69d66290..00000000 --- a/scheme/arm-cca/endorsement_handler_test.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package arm_cca - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDecoder_GetAttestationScheme(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetAttestationScheme() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetSupportedMediaTypes(t *testing.T) { - d := &EndorsementHandler{} - - expected := EndorsementMediaTypes - - actual := d.GetSupportedMediaTypes() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_Init(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Init(nil)) -} - -func TestDecoder_Close(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Close()) -} - -func TestDecoder_Decode_empty_data(t *testing.T) { - d := &EndorsementHandler{} - - emptyData := []byte{} - - expectedErr := `empty data` - - _, err := d.Decode(emptyData, "", nil) - - assert.EqualError(t, err, expectedErr) -} - -func TestDecoder_Decode_invalid_data(t *testing.T) { - d := &EndorsementHandler{} - - invalidCbor := []byte("invalid CBOR") - - expectedErr := `CBOR decoding failed` - - _, err := d.Decode(invalidCbor, "", nil) - - assert.ErrorContains(t, err, expectedErr) -} - -func TestDecoder_Decode_CcaSsdRefVal_OK(t *testing.T) { - tvs := [][]byte{ - unsignedCorimCcaComidCcaRefValOne, - unsignedCorimCcaComidCcaRefValFour, - } - - d := &EndorsementHandler{} - - for _, tv := range tvs { - _, err := d.Decode(tv, "", nil) - assert.NoError(t, err) - } -} - -func TestDecoder_Decode_CCaSsdRefVal_NOK(t *testing.T) { - tvs := []struct { - desc string - input []byte - expectedErr string - }{ - { - desc: "missing profile inside corim containing one CCA platform config measurement", - input: unsignedCorimCcaNoProfileComidCcaRefValOne, - expectedErr: "no profile information set in CoRIM", - }, - { - desc: "missing profile inside corim containing multiple reference value measurements", - input: unsignedCorimCcaNoProfileComidCcaRefValFour, - expectedErr: "no profile information set in CoRIM", - }, - } - - for _, tv := range tvs { - d := &EndorsementHandler{} - _, err := d.Decode(tv.input, "", nil) - assert.EqualError(t, err, tv.expectedErr) - } -} - -func TestDecoder_DecodeCcaRealm_OK(t *testing.T) { - tvs := [][]byte{ - unsignedCorimCcaRealmComidCcaRealm, - unsignedCorimCcaRealmComidCcaRealmNoClass, - } - - d := &EndorsementHandler{} - - for _, tv := range tvs { - _, err := d.Decode(tv, "", nil) - assert.NoError(t, err) - } -} - -func TestDecoder_DecodeCcaRealm_negative_tests(t *testing.T) { - tvs := []struct { - desc string - input []byte - expectedErr string - }{ - { - desc: "no realm instance identity in corim", - input: unsignedCorimCcaRealmComidCcaRealmNoInstance, - expectedErr: "bad software component in CoMID at index 0: could not extract Realm instance attributes: expecting instance in environment", - }, - { - desc: "invalid instance identity in corim", - input: unsignedCorimCcaRealmComidCcaRealmInvalidInstance, - expectedErr: "bad software component in CoMID at index 0: could not extract Realm instance attributes: expecting instance as bytes for CCA Realm", - }, - { - desc: "invalid class identity in corim", - input: unsignedCorimCcaRealmComidCcaRealmInvalidClass, - expectedErr: "bad software component in CoMID at index 0: could not extract Realm class attributes: could not extract uuid from class-id: class-id type is: *comid.TaggedImplID", - }, - } - - for _, tv := range tvs { - t.Run(tv.desc, func(t *testing.T) { - d := &EndorsementHandler{} - _, err := d.Decode(tv.input, "", nil) - assert.EqualError(t, err, tv.expectedErr) - }) - } -} diff --git a/scheme/arm-cca/evidence_handler.go b/scheme/arm-cca/evidence_handler.go deleted file mode 100644 index 0df93b71..00000000 --- a/scheme/arm-cca/evidence_handler.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "fmt" - - "github.com/veraison/ccatoken" - "github.com/veraison/ear" - "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{} - -func (s EvidenceHandler) GetName() string { - return "cca-evidence-handler" -} - -func (s EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func (s EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - ccaToken, err := ccatoken.DecodeAndValidateEvidenceFromCBOR(token.Data) - if err != nil { - return nil, handler.BadEvidence(err) - } - - platformClaimsSet, err := common.ClaimsToMap(common.CcaPlatformWrapper{ccaToken.PlatformClaims}) // nolint:govet - if err != nil { - return nil, handler.BadEvidence(fmt.Errorf( - "could not convert platform claims: %w", err)) - } - - realmClaimsSet, err := common.ClaimsToMap(common.CcaRealmWrapper{ccaToken.RealmClaims}) // nolint:govet - if err != nil { - return nil, handler.BadEvidence(fmt.Errorf( - "could not convert realm claims: %w", err)) - } - - claims := map[string]interface{}{ - "platform": platformClaimsSet, - "realm": realmClaimsSet, - } - - return claims, nil -} - -// ValidateEvidenceIntegrity, decodes CCA collection and then invokes Verify API of ccatoken library -// which verifies the signature on the platform part of CCA collection, using supplied trust anchor -// and internally verifies the realm part of CCA token using realm public key extracted from -// realm token. -func (s EvidenceHandler) ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - endorsementsStrings []string, -) error { - ccaToken, err := ccatoken.DecodeAndValidateEvidenceFromCBOR(token.Data) - if err != nil { - return handler.BadEvidence(err) - } - - realmChallenge, err := ccaToken.RealmClaims.GetChallenge() - if err != nil { - return handler.BadEvidence(err) - } - - // If the provided challenge was less than 64 bytes long, the RMM will - // zero-pad pad it when generating the attestation token, so do the - // same to the session nonce. - sessionNonce := make([]byte, 64) - copy(sessionNonce, token.Nonce) - - if !bytes.Equal(realmChallenge, sessionNonce) { - return handler.BadEvidence( - "freshness: realm challenge (%s) does not match session nonce (%s)", - hex.EncodeToString(realmChallenge), - hex.EncodeToString(token.Nonce), - ) - } - - pk, err := arm.GetPublicKeyFromTA(SchemeName, trustAnchors[0]) - if err != nil { - return fmt.Errorf("could not get public key from trust anchor: %w", err) - } - - if err = ccaToken.Verify(pk); err != nil { - return handler.BadEvidence(err) - } - log.Debug("CCA platform token signature, realm token signature and cryptographic binding verified") - return nil -} - -func (s EvidenceHandler) AppraiseEvidence( - ec *proto.EvidenceContext, endorsementsStrings []string, -) (*ear.AttestationResult, error) { - endorsements, err := getEndorsementsFromString(endorsementsStrings) - if err != nil { - return nil, err - } - evidence := ec.Evidence.AsMap() - result := handler.CreateAttestationResult("CCA_SSD_PLATFORM") - - /* Perform SubAttester Appraisal */ - claims, ok := evidence["platform"].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("unable to get platform claims: %w", handler.BadEvidence(err)) - } - - appraisal, err := platformAppraisal(claims, endorsements) - if err != nil { - return nil, err - } - result.Submods["CCA_SSD_PLATFORM"] = appraisal - claims, ok = evidence["realm"].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("unable to get realm claims: %w", handler.BadEvidence(err)) - } - - appraisal, err = realmAppraisal(claims, endorsements) - if err != nil { - return nil, err - } - result.Submods["CCA_REALM"] = appraisal - return result, nil -} - -func getEndorsementsFromString(endorsementsStrings []string) ([]handler.Endorsement, error) { - var endorsements []handler.Endorsement // nolint:prealloc - for i, e := range endorsementsStrings { - var endorsement handler.Endorsement - - if err := json.Unmarshal([]byte(e), &endorsement); err != nil { - return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err) - } - endorsements = append(endorsements, endorsement) - } - return endorsements, nil -} diff --git a/scheme/arm-cca/evidence_handler_test.go b/scheme/arm-cca/evidence_handler_test.go deleted file mode 100644 index f37e4b98..00000000 --- a/scheme/arm-cca/evidence_handler_test.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/ear" - "github.com/veraison/services/proto" -) - -func Test_AppraiseEvidence_Platform_ok(t *testing.T) { // nolint: dupl - extractedBytes, err := os.ReadFile("test/evidence/extracted.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/platform/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_SSD_PLATFORM"] - - assert.Equal(t, ear.TrustTierAffirming, *attestation.Status) - assert.Equal(t, attestation.TrustVector.Executables, ear.ApprovedRuntimeClaim) - assert.Equal(t, attestation.TrustVector.Configuration, ear.ApprovedConfigClaim) -} - -func Test_AppraiseEvidence_mismatch_refval_meas(t *testing.T) { // nolint: dupl - extractedBytes, err := os.ReadFile("test/evidence/extracted.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/platform/mismatch-refval-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_SSD_PLATFORM"] - - assert.Equal(t, ear.TrustTierWarning, *attestation.Status) - assert.Equal(t, attestation.TrustVector.Executables, ear.UnrecognizedRuntimeClaim) - assert.Equal(t, attestation.TrustVector.Configuration, ear.ApprovedConfigClaim) -} - -func Test_AppraiseEvidence_mismatch_refval_cfg(t *testing.T) { // nolint: dupl - extractedBytes, err := os.ReadFile("test/evidence/extracted.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/platform/mismatch-cfg-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_SSD_PLATFORM"] - - assert.Equal(t, ear.TrustTierWarning, *attestation.Status) - assert.Equal(t, attestation.TrustVector.Executables, ear.ApprovedRuntimeClaim) - assert.Equal(t, attestation.TrustVector.Configuration, ear.UnsafeConfigClaim) -} - -func Test_AppraiseEvidence_Realm(t *testing.T) { // nolint: dupl - tvs := []struct { - desc string - input string - expectedStatus ear.TrustTier - expectedExec ear.TrustClaim - }{ - { - desc: "No realm endorsements", - input: "test/realm/no-realm-endorsements.json", - expectedStatus: ear.TrustTierWarning, - expectedExec: ear.UnrecognizedRuntimeClaim, - }, - - { - desc: "No matching rim measurements", - input: "test/realm/rim-mismatch-endorsements.json", - expectedStatus: ear.TrustTierNone, - expectedExec: ear.VerifierMalfunctionClaim, - }, - { - desc: "matching rim & rpv, no rem", - input: "test/realm/no-rem-endorsements.json", - expectedStatus: ear.TrustTierAffirming, - expectedExec: ear.ApprovedBootClaim, - }, - { - desc: "matching rim & rem, no rpv", - input: "test/realm/no-rpv-endorsements.json", - expectedStatus: ear.TrustTierAffirming, - expectedExec: ear.ApprovedRuntimeClaim, - }, - { - desc: "matching rim, rpv and rem measurements", - input: "test/realm/match-endorsements.json", - expectedStatus: ear.TrustTierAffirming, - expectedExec: ear.ApprovedRuntimeClaim, - }, - } - for _, tv := range tvs { - extractedBytes, err := os.ReadFile("test/evidence/extracted.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(tv.input) - 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, tv.expectedStatus, *attestation.Status) - assert.Equal(t, tv.expectedExec, attestation.TrustVector.Executables) - } -} - -func Test_ExtractVerifiedClaims_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/cca-token.cbor") - require.NoError(t, err) - taEndValBytes, err := os.ReadFile("test/platform/ta-endorsements.json") - require.NoError(t, err) - scheme := &EvidenceHandler{} - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - ta := string(taEndValBytes) - extracted, err := scheme.ExtractClaims(&token, []string{ta}) - platformClaims := extracted["platform"].(map[string]interface{}) - require.NoError(t, err) - assert.Equal(t, "http://arm.com/CCA-SSD/1.0.0", - platformClaims["cca-platform-profile"].(string)) - swComponents := platformClaims["cca-platform-sw-components"].([]interface{}) - assert.Len(t, swComponents, 4) - assert.Equal(t, "BL", swComponents[0].(map[string]interface{})["measurement-type"].(string)) - ccaPlatformCfg := platformClaims["cca-platform-config"] - assert.Equal(t, "AQID", ccaPlatformCfg) -} - -func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/cca-token.cbor") - require.NoError(t, err) - taEndValBytes, err := os.ReadFile("test/platform/ta-endorsements.json") - require.NoError(t, err) - scheme := &EvidenceHandler{} - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - ta := string(taEndValBytes) - err = scheme.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - assert.NoError(t, err) -} - -func Test_ValidateEvidenceIntegrity_invalid_key(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/cca-token.cbor") - require.NoError(t, err) - taEndValBytes, err := os.ReadFile("test/platform/invalid-key-ta-endorsements.json") - require.NoError(t, err) - scheme := &EvidenceHandler{} - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - expectedErr := `could not get public key from trust anchor: could not decode subject public key info: unsupported key type: "PRIVATE KEY"` - ta := string(taEndValBytes) - err = scheme.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - assert.EqualError(t, err, expectedErr) -} - -func Test_GetSupportedMediaType_ok(t *testing.T) { - expectedMt := `application/eat-collection; profile="http://arm.com/CCA-SSD/1.0.0"` - scheme := &EvidenceHandler{} - mtList := scheme.GetSupportedMediaTypes() - assert.Len(t, mtList, 1) - assert.Equal(t, mtList[0], expectedMt) -} diff --git a/scheme/arm-cca/platform.go b/scheme/arm-cca/platform.go deleted file mode 100644 index 03df32f5..00000000 --- a/scheme/arm-cca/platform.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import ( - "fmt" - - "github.com/veraison/ccatoken/platform" - "github.com/veraison/ear" - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common" - "github.com/veraison/services/scheme/common/arm" -) - -func platformAppraisal( - claimsMap map[string]interface{}, - endorsements []handler.Endorsement, -) (*ear.Appraisal, error) { - claims, err := common.MapToCCAPlatformClaims(claimsMap) - if err != nil { - return nil, fmt.Errorf("unable to get claims from platform claims map: %w", err) - } - - trustVector := ear.TrustVector{} - // once the signature on the token is verified, we can claim the HW is - // authentic - trustVector.Hardware = ear.GenuineHardwareClaim - rawLifeCycle, err := claims.GetSecurityLifeCycle() - if err != nil { - return nil, handler.BadEvidence(err) - } - - lifeCycle := platform.LifeCycleToState(rawLifeCycle) - if lifeCycle == platform.StateSecured || - lifeCycle == platform.StateNonCCAPlatformDebug { - trustVector.InstanceIdentity = ear.TrustworthyInstanceClaim - trustVector.RuntimeOpaque = ear.ApprovedRuntimeClaim - trustVector.StorageOpaque = ear.HwKeysEncryptedSecretsClaim - } else { - trustVector.InstanceIdentity = ear.UntrustworthyInstanceClaim - trustVector.RuntimeOpaque = ear.VisibleMemoryRuntimeClaim - trustVector.StorageOpaque = ear.UnencryptedSecretsClaim - } - - swComps := arm.FilterRefVal(endorsements, "platform.sw-component") - match := arm.MatchSoftware(SchemeName, claims, swComps) - if match { - trustVector.Executables = ear.ApprovedRuntimeClaim - - } else { - trustVector.Executables = ear.UnrecognizedRuntimeClaim - } - - platformConfig := arm.FilterRefVal(endorsements, "platform.config") - match = arm.MatchPlatformConfig(SchemeName, claims, platformConfig) - - if match { - trustVector.Configuration = ear.ApprovedConfigClaim - - } else { - trustVector.Configuration = ear.UnsafeConfigClaim - } - - var status ear.TrustTier - appraisal := ear.Appraisal{ - Status: &status, - TrustVector: &trustVector, - } - - appraisal.UpdateStatusFromTrustVector() - appraisal.VeraisonAnnotatedEvidence = &claimsMap - return &appraisal, nil -} diff --git a/scheme/arm-cca/plugin/Makefile b/scheme/arm-cca/plugin/Makefile index 33a74ffc..976afb7d 100644 --- a/scheme/arm-cca/plugin/Makefile +++ b/scheme/arm-cca/plugin/Makefile @@ -1,11 +1,11 @@ +# Copyright 2021-2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += endorsement-handler - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-arm-cca.plugin +GOPKG := github.com/veraison/services/scheme/arm-cca +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/arm-cca/plugin/combined/Makefile b/scheme/arm-cca/plugin/combined/Makefile deleted file mode 100644 index ec6dd9bc..00000000 --- a/scheme/arm-cca/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/arm-cca.plugin -GOPKG := github.com/veraison/services/scheme/arm-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/arm-cca/plugin/combined/main.go b/scheme/arm-cca/plugin/combined/main.go deleted file mode 100644 index f9458855..00000000 --- a/scheme/arm-cca/plugin/combined/main.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/arm-cca" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/arm-cca/plugin/endorsement-handler/Makefile b/scheme/arm-cca/plugin/endorsement-handler/Makefile deleted file mode 100644 index d319feaa..00000000 --- a/scheme/arm-cca/plugin/endorsement-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/arm-cca-endorsement-handler.plugin -GOPKG := github.com/veraison/services/scheme/arm-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/arm-cca/plugin/endorsement-handler/main.go b/scheme/arm-cca/plugin/endorsement-handler/main.go deleted file mode 100644 index 3520cd06..00000000 --- a/scheme/arm-cca/plugin/endorsement-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/arm-cca" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - plugin.Serve() -} diff --git a/scheme/arm-cca/plugin/evidence-handler/Makefile b/scheme/arm-cca/plugin/evidence-handler/Makefile deleted file mode 100644 index 337da3f0..00000000 --- a/scheme/arm-cca/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/arm-cca-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/arm-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/arm-cca/plugin/evidence-handler/main.go b/scheme/arm-cca/plugin/main.go similarity index 61% rename from scheme/arm-cca/plugin/evidence-handler/main.go rename to scheme/arm-cca/plugin/main.go index 9669bebb..e0774090 100644 --- a/scheme/arm-cca/plugin/evidence-handler/main.go +++ b/scheme/arm-cca/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2022-2024 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) plugin.Serve() } diff --git a/scheme/arm-cca/plugin/store-handler/Makefile b/scheme/arm-cca/plugin/store-handler/Makefile deleted file mode 100644 index c31926f7..00000000 --- a/scheme/arm-cca/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/arm-cca-store-handler.plugin -GOPKG := github.com/veraison/services/scheme/arm-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/arm-cca/plugin/store-handler/main.go b/scheme/arm-cca/plugin/store-handler/main.go deleted file mode 100644 index 1cbf2d6e..00000000 --- a/scheme/arm-cca/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/arm-cca" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/arm-cca/realm.go b/scheme/arm-cca/realm.go deleted file mode 100644 index f29ee373..00000000 --- a/scheme/arm-cca/realm.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import ( - "bytes" - "encoding/base64" - "errors" - "fmt" - - ccatokenrealm "github.com/veraison/ccatoken/realm" - "github.com/veraison/ear" - "github.com/veraison/services/handler" - "github.com/veraison/services/log" - "github.com/veraison/services/scheme/common/arm" - "github.com/veraison/services/scheme/common/cca/realm" -) - -var ( - ErrKeyNotFound = errors.New("key not found") - ErrValuesMismatch = errors.New("values mismatch") -) - -func realmAppraisal( - claimsMap map[string]interface{}, - endorsements []handler.Endorsement) (*ear.Appraisal, error) { - realmEndorsements := arm.FilterRefVal(endorsements, "realm.reference-value") - claims, err := realm.MapToRealmClaims(claimsMap) - if err != nil { - return nil, fmt.Errorf("unable to get claims from realm claims map: %w", err) - } - - trustVector := ear.TrustVector{} - // If crypto verification (including chaining) completes correctly, - // we can safely assume the Realm instance to be trustworthy - trustVector.InstanceIdentity = ear.TrustworthyInstanceClaim - trustVector.Executables = ear.UnrecognizedRuntimeClaim - - for _, endorsement := range realmEndorsements { - if matchRim(claims, &endorsement) { - err := matchRpv(claims, &endorsement) - switch err { - // Note, If an Endorser does not use RPV it indicates, one Realm per RIM, which is a match - case nil, ErrKeyNotFound: - trustVector.Executables = ear.ApprovedBootClaim - case ErrValuesMismatch: - trustVector.Executables = ear.ContraindicatedRuntimeClaim - continue // continue looking for other RPVs matching the same RIM - default: - // Some serious error has happened, report it as VerifierMalfunction - log.Errorf("fatal error in matchRpv %w", err) - trustVector.SetAll(ear.VerifierMalfunctionClaim) - } - - // Only match REMs when RIM and RPV match - if trustVector.Executables == ear.ApprovedBootClaim { - // Match REM's - if matchREMs(claims, &endorsement) { - trustVector.Executables = ear.ApprovedRuntimeClaim - } - } - break - } else { - // For this CCA Realm scheme, as RIM fetches all the Endorsements, for now - // failure to match RIM means some serious issue with the Verifier - trustVector.SetAll(ear.VerifierMalfunctionClaim) - } - } - var status ear.TrustTier - appraisal := ear.Appraisal{ - Status: &status, - TrustVector: &trustVector, - } - - appraisal.UpdateStatusFromTrustVector() - appraisal.VeraisonAnnotatedEvidence = &claimsMap - - return &appraisal, nil -} - -func matchRim(claims ccatokenrealm.IClaims, endorsement *handler.Endorsement) bool { - // get RIM Claim from Evidence Claims - rimClaim, err := claims.GetInitialMeasurement() - if err != nil { - log.Errorf("failed to extract rim measurements: %w", err) - return false - } - // get RIM from endorsements - r, err := realm.GetRIM(endorsement.Attributes) - if err != nil { - log.Errorf("unable to get rim endorsements: %w", err) - return false - } - rim, err := base64.StdEncoding.DecodeString(r) - if err != nil { - log.Errorf("base64 decode failed: %w", err) - return false - } - if !bytes.Equal(rimClaim, rim) { - log.Errorf("fatal error in Rim matching, evidence rim %v, endorsement rim %v", rimClaim, rim) - return false - } - return true -} - -func matchRpv(claims ccatokenrealm.IClaims, endorsement *handler.Endorsement) error { - pvClaim, err := claims.GetPersonalizationValue() - if err != nil { - return fmt.Errorf("matchRpv failed: %w", err) - } - rpv, err := realm.GetRPV(endorsement.Attributes) - if err != nil { - return fmt.Errorf("unable to get rpv endorsements: %w", err) - } - if rpv == nil { - return ErrKeyNotFound - } - if !bytes.Equal(pvClaim, rpv) { - return ErrValuesMismatch - } - return nil -} - -func matchREMs(claims ccatokenrealm.IClaims, endorsement *handler.Endorsement) bool { - remMatch := false - remsClaim, err := claims.GetExtensibleMeasurements() - if err != nil { - log.Errorf("unable to get realm extensible measurements from claims: %w", err) - return remMatch - } - rems, err := realm.GetREMs(endorsement.Attributes) - if err != nil { - log.Errorf("unable to get REM endorsements: %w", err) - return remMatch - } - for i, rem := range rems { - if bytes.Equal(remsClaim[i], rem) { - log.Debugf("Realm Extended Measurement match at index: %d", i) - remMatch = true - } else { - log.Debugf("Realm Extended Measurement does not match at index: %d", i) - remMatch = false - break /* the rem loop */ - } - } - return remMatch -} diff --git a/scheme/arm-cca/scheme.go b/scheme/arm-cca/scheme.go index e4c01768..4fda77ad 100644 --- a/scheme/arm-cca/scheme.go +++ b/scheme/arm-cca/scheme.go @@ -1,26 +1,555 @@ -// Copyright 2024-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package arm_cca -const SchemeName = "ARM_CCA" +import ( + "bytes" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" -var ( - EndorsementMediaTypes = []string{ - // Unsigned CoRIM profiles - `application/corim-unsigned+cbor; profile="http://arm.com/cca/ssd/1"`, - `application/corim-unsigned+cbor; profile="http://arm.com/cca/realm/1"`, - `application/rim+cbor; profile="tag:arm.com,2023:cca_platform#1.0.0"`, - `application/rim+cbor; profile="tag:arm.com,2023:realm#1.0.0"`, - // Signed CoRIM profiles - `application/rim+cose; profile="http://arm.com/cca/ssd/1"`, - `application/rim+cose; profile="http://arm.com/cca/realm/1"`, - } + "github.com/veraison/ccatoken" + "github.com/veraison/ccatoken/platform" + "github.com/veraison/ccatoken/realm" + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + "github.com/veraison/services/scheme/common" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" +) - EvidenceMediaTypes = []string{ +var Descriptor = handler.SchemeDescriptor{ + Name: "ARM_CCA", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + LegacyPlatformProfileString, + LegacyRealmProfileString, + PlatformProfileString, + RealmProfileString, + }, + EvidenceMediaTypes: []string{ `application/eat-collection; profile="http://arm.com/CCA-SSD/1.0.0"`, + }, +} + +type Implementation struct { + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), } +} - CoservMediaTypes = []string{ - `application/coserv+cbor; profile="tag:arm.com,2023:cca_platform#1.0.0"`, +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + ccaToken, err := ccatoken.DecodeAndValidateEvidenceFromCBOR(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) } -) + + implIDbytes, err := ccaToken.PlatformClaims.GetImplID() + if err != nil { + return nil, err + } + + instIDbytes, err := ccaToken.PlatformClaims.GetInstID() + if err != nil { + return nil, err + } + + classID, err := comid.NewImplIDClassID(implIDbytes) + if err != nil { + return nil, err + } + + instanceID, err := comid.NewUEIDInstance(instIDbytes) + if err != nil { + return nil, err + } + + return []*comid.Environment{ + { + Class: &comid.Class{ClassID: classID}, + Instance: instanceID, + }, + }, nil +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + numTAs := len(trustAnchors) + if numTAs != 1 { + return nil, fmt.Errorf("expected exactly 1 trust anchor; got %d", numTAs) + } + + realmEntry, ok := claims["realm"] + if !ok { + return nil, errors.New(`no "realm" entry in claims`) + } + + realmClaims, err := convertToRealmClaims(realmEntry) + if err != nil { + return nil, err + } + + rimValue, err := realmClaims.GetInitialMeasurement() + if err != nil { + return nil, err + } + + return []*comid.Environment{ + { + Class: trustAnchors[0].Environment.Class, + }, + { + Instance: comid.MustNewBytesInstance(rimValue), + }, + }, nil +} + +func (o *Implementation) ValidateComid(c *comid.Comid) error { + return nil +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + ccaToken, err := ccatoken.DecodeAndValidateEvidenceFromCBOR(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + platformClaims, err := common.ToMapViaJSON(ccaToken.PlatformClaims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + realmClaims, err := common.ToMapViaJSON(ccaToken.RealmClaims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + claims := map[string]any{ + "platform": platformClaims, + "realm": realmClaims, + } + + return claims, nil +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + pk, err := common.ExtractPublicKeyFromTrustAnchors(trustAnchors) + if err != nil { + return fmt.Errorf("could not get public key from trust anchors: %w", err) + } + + ccaToken, err := ccatoken.DecodeAndValidateEvidenceFromCBOR(evidence.Data) + if err != nil { + return handler.BadEvidence(err) + } + + realmChallenge, err := ccaToken.RealmClaims.GetChallenge() + if err != nil { + return handler.BadEvidence(err) + } + + // If the provided challenge was less than 64 bytes long, the RMM will + // zero-pad pad it when generating the attestation token, so do the + // same to the session nonce. + sessionNonce := make([]byte, 64) + copy(sessionNonce, evidence.Nonce) + + if !bytes.Equal(realmChallenge, sessionNonce) { + return handler.BadEvidence( + "freshness: realm challenge (%s) does not match session nonce (%s)", + hex.EncodeToString(realmChallenge), + hex.EncodeToString(evidence.Nonce), + ) + } + + if err = ccaToken.Verify(pk); err != nil { + return handler.BadEvidence(err) + } + o.logger.Info("Token signature verified.") + + return nil +} + +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult("CCA_SSD_PLATFORM") + + platformEntry, ok := claims["platform"] + if !ok { + return result, errors.New(`no "platform" entry in claims`) + } + + err := AppraisePlatform(o.logger, result.Submods["CCA_SSD_PLATFORM"], platformEntry, endorsements) + if err != nil { + return result, err + } + + realmEntry, ok := claims["realm"] + if !ok { + return result, errors.New(`no "realm" entry in claims`) + } + + appraisal := ear.NewAppraisal() + err = AppraiseRealm(o.logger, appraisal, realmEntry, endorsements) + if err != nil { + return result, err + } + result.Submods["CCA_REALM"] = appraisal + + return result, nil +} + +func AppraisePlatform( + logger *zap.SugaredLogger, + appraisal *ear.Appraisal, + entry any, + endorsements []*comid.ValueTriple, +) error { + claims, err := convertToPlatformClaims(entry) + if err != nil { + return handler.BadEvidence(err) + } + + // once the signature on the token is verified, we can claim the HW is + // authentic + appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim + + rawLifeCycle, err := claims.GetSecurityLifeCycle() + if err != nil { + return handler.BadEvidence(err) + } + + lifeCycle := platform.LifeCycleToState(rawLifeCycle) + if lifeCycle == platform.StateSecured || + lifeCycle == platform.StateNonCCAPlatformDebug { + 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 + } + + platformMatched, swMatched, err := matchPlatformClaimsToReferenceValues(logger, claims, endorsements) + if err != nil { + return err + } + + if platformMatched { + appraisal.TrustVector.Configuration = ear.ApprovedConfigClaim + + } else { + appraisal.TrustVector.Configuration = ear.UnsafeConfigClaim + } + + if swMatched { + appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim + + } else { + appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim + } + + claimsMap, err := common.ToMapViaJSON(claims) + if err != nil { + return err + } + + appraisal.UpdateStatusFromTrustVector() + appraisal.VeraisonAnnotatedEvidence = &claimsMap + return nil +} + +type realmReference struct { + PersonalizationValue []byte + InitialMeasurement []byte + ExtensibleMeasurements [][]byte +} + +func AppraiseRealm( + logger *zap.SugaredLogger, + appraisal *ear.Appraisal, + entry any, + endorsements []*comid.ValueTriple, +) error { + claims, err := convertToRealmClaims(entry) + if err != nil { + return handler.BadEvidence(err) + } + + evidenceRIM, err := claims.GetInitialMeasurement() + if err != nil { + return handler.BadEvidence(err) + } + + evidenceREMs, err := claims.GetExtensibleMeasurements() + if err != nil { + return handler.BadEvidence(err) + } + + evidencePV, err := claims.GetPersonalizationValue() + if err != nil { + return handler.BadEvidence(err) + } + + // If crypto verification (including chaining) completes correctly, + // we can safely assume the Realm instance to be trustworthy + appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim + appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim + + referenceValues := make([]realmReference, 0, len(endorsements)) + for _, triple := range endorsements { + // unset Instance indicates platform endorsements + if triple.Environment.Instance == nil { + continue + } + + for _, measurement := range triple.Measurements.Values { + refVal := realmReference{} + + if measurement.Val.RawValue != nil { + refVal.PersonalizationValue, err = measurement.Val.RawValue.GetBytes() + if err != nil { + return fmt.Errorf("personalization value: %w", err) + } + } + + if measurement.Val.IntegrityRegisters == nil { + return errors.New("integrity registers not set in realm reference") + } + + numREMs := len(measurement.Val.IntegrityRegisters.IndexMap) - 1 + refVal.ExtensibleMeasurements = make([][]byte, numREMs) + + for key, digests := range measurement.Val.IntegrityRegisters.IndexMap { + dLen := len(digests) + if dLen != 1 { + return fmt.Errorf("expected 1 digest for integ. reg.; found %d", dLen) + } + + keyText, ok := key.(string) + if !ok { + return fmt.Errorf("non-string integ. reg. key: %v", key) + } + + if keyText == "rim" { + refVal.InitialMeasurement = digests[0].HashValue + } else { + idxText := strings.Replace(keyText, "rem", "", 1) + idx, err := strconv.Atoi(idxText) + if err != nil { + return fmt.Errorf("bad REM key: %s", keyText) + } + + refVal.ExtensibleMeasurements[idx] = digests[0].HashValue + } + } + + referenceValues = append(referenceValues, refVal) + } + } + + for _, refVal := range referenceValues { + if !bytes.Equal(refVal.InitialMeasurement, evidenceRIM) { + // For this CCA Realm scheme, as RIM fetches all the Endorsements, for now + // failure to match RIM means some serious issue with the Verifier + appraisal.TrustVector.SetAll(ear.VerifierMalfunctionClaim) + break + } + + // Note: if an Endorser does not use RPV it indicates one Realm per RIM, which is a match + if refVal.PersonalizationValue != nil && !bytes.Equal(refVal.PersonalizationValue, evidencePV) { + appraisal.TrustVector.Executables = ear.ContraindicatedRuntimeClaim + continue // continue looking for other RPVs matching the same RIM + } + + appraisal.TrustVector.Executables = ear.ApprovedBootClaim + logger.Debug("RIM & RPV matched") + + if allMatch(refVal.ExtensibleMeasurements, evidenceREMs) { + appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim + logger.Debug("REMs matched") + } else { + logger.Debug("REMs failed to match") + } + + break + } + + claimsMap, err := common.ToMapViaJSON(claims) + if err != nil { + return err + } + + appraisal.UpdateStatusFromTrustVector() + appraisal.VeraisonAnnotatedEvidence = &claimsMap + + return nil +} + +func convertToRealmClaims(v any) (realm.IClaims, error) { + encoded, err := json.Marshal(v) + if err != nil { + return nil, err + } + + return realm.DecodeClaimsFromJSON(encoded) +} + +func convertToPlatformClaims(v any) (platform.IClaims, error) { + encoded, err := json.Marshal(v) + if err != nil { + return nil, err + } + + return platform.DecodeClaimsFromJSON(encoded) +} + +func matchPlatformClaimsToReferenceValues( + logger *zap.SugaredLogger, + claims platform.IClaims, + endorsements []*comid.ValueTriple, +) (bool, bool, error) { + var err error + var referenceConfigValue []byte + + referenceValues := make(map[string][2]string) + for _, triple := range endorsements { + // set Instance indicates realm endorsements + if triple.Environment.Instance != nil { + continue + } + + for _, measurement := range triple.Measurements.Values { + _, err = measurement.Key.GetCCAPlatformConfigID() + if err == nil { + if measurement.Val.RawValue == nil { + return false, false, + errors.New("no raw value in platform config measurement") + } + + referenceConfigValue, err = measurement.Val.RawValue.GetBytes() + if err != nil { + return false, false, err + } + + continue + } + + // not platform config entry, therefore must be a S/W component entry. + refValID, err := measurement.Key.GetPSARefValID() + if err != nil { + return false, false, err + } + + if measurement.Val.Digests == nil { + return false, false, errors.New("no digests in reference value measurement") + } + + numDigests := len(*measurement.Val.Digests) + if numDigests != 1 { + return false, false, fmt.Errorf( + "expected exactly 1 digest in measurement; found %d", + numDigests, + ) + } + + encoded := base64.StdEncoding.EncodeToString((*measurement.Val.Digests)[0].HashValue) + referenceValues[encoded] = [2]string{*refValID.Label, *refValID.Version} + } + } + + evidenceConfigValue, err := claims.GetConfig() + if err != nil { + return false, false, handler.BadEvidence(err) + } + + configMatched := false + if bytes.Equal(evidenceConfigValue, referenceConfigValue) { + logger.Debug("platform config matched") + configMatched = true + } else { + logger.Debug("platform config failed to match") + } + + swComponents, err := claims.GetSoftwareComponents() + if err != nil { + return false, false, handler.BadEvidence(err) + } + + for i, swComp := range swComponents { + mval, err := swComp.GetMeasurementValue() + if err != nil { + return false, false, handler.BadEvidence(fmt.Errorf("S/W comp. %d value: %w", i, err)) + } + mvalEncoded := base64.StdEncoding.EncodeToString(mval) + + mtype, err := swComp.GetMeasurementType() + if err != nil { + return false, false, handler.BadEvidence(fmt.Errorf("S/W comp. %d type: %w", i, err)) + } + + mversion, err := swComp.GetVersion() + if err != nil { + return false, false, handler.BadEvidence(fmt.Errorf("S/W comp. %d version: %w", i, err)) + } + + rvInfo, matched := referenceValues[mvalEncoded] + if !matched { + logger.Debugf("S/W comp. %d measurement (%s) failed to match", i, mvalEncoded) + return configMatched, false, nil + } + logger.Debugf("S/W comp. %d measurement (%s) matched", i, mvalEncoded) + refValLabel := rvInfo[0] + refValVersion := rvInfo[1] + + typeMatched := refValLabel == "" || mtype == refValLabel + versionMatched := refValVersion == "" || mversion == refValVersion + logger.Debugf("S/W comp. %d type matched: %t (%s), version matched: %t (%s)", + i, typeMatched, mtype, versionMatched, mversion) + + if !typeMatched || !versionMatched { + return configMatched, false, nil + } + } + + return configMatched, true, nil +} + +func allMatch(lhs, rhs [][]byte) bool { + if len(lhs) != len(rhs) { + return false + } + + for i, lhsV := range lhs { + if !bytes.Equal(lhsV, rhs[i]) { + return false + } + } + + return true +} diff --git a/scheme/arm-cca/store_handler.go b/scheme/arm-cca/store_handler.go deleted file mode 100644 index b197d49b..00000000 --- a/scheme/arm-cca/store_handler.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2024-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import ( - "encoding/base64" - "errors" - "fmt" - - "github.com/veraison/ccatoken" - "github.com/veraison/corim/comid" - "github.com/veraison/corim/coserv" - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" - "github.com/veraison/services/scheme/common/arm" - "github.com/veraison/services/scheme/common/cca/realm" -) - -type StoreHandler struct{} - -func (s StoreHandler) GetName() string { - return "cca-store-handler" -} - -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -func (s StoreHandler) SynthKeysFromRefValue( - tenantID string, - refVal *handler.Endorsement, -) ([]string, error) { - switch refVal.SubType { - case "platform.sw-component", "platform.config": - return arm.SynthKeysForPlatform(SchemeName, tenantID, refVal) - case "realm.reference-value": - return realm.SynthKeysForCcaRealm(SchemeName, tenantID, refVal) - default: - return nil, fmt.Errorf("invalid SubType: %s, for Scheme: %s", refVal.SubType, refVal.Scheme) - } -} - -func (s StoreHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) { - return arm.SynthKeysFromTrustAnchors(SchemeName, tenantID, ta) -} - -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - evidence, err := ccatoken.DecodeAndValidateEvidenceFromCBOR(token.Data) - if err != nil { - return []string{""}, handler.BadEvidence(err) - } - - claims := evidence.PlatformClaims - if err != nil { - return []string{""}, err - } - taID, err := arm.GetTrustAnchorID(SchemeName, token.TenantId, claims) - if err != nil { - return []string{""}, err - } - - return []string{taID}, nil -} - -func (s StoreHandler) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - platformClaimsMap, ok := claims["platform"].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("claims do not contain platform map: %v", claims) - } - pids, err := arm.GetPlatformReferenceIDs(SchemeName, tenantID, platformClaimsMap) - if err != nil { - return nil, fmt.Errorf("unable to get cca platform reference IDs: %w", err) - } - realmClaimsMap, ok := claims["realm"].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("claims do not contain realm map: %v", claims) - } - rids, err := realm.GetRealmReferenceIDs(SchemeName, tenantID, realmClaimsMap) - if err != nil { - return nil, fmt.Errorf("unable to get cca realm reference IDs: %w", err) - } - return append(pids, rids...), nil -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - var q coserv.Coserv - if err := q.FromBase64Url(query); err != nil { - return nil, err - } - - var keys []string - - switch q.Query.ArtifactType { - case coserv.ArtifactTypeReferenceValues: - s := q.Query.EnvironmentSelector - - if s.Classes != nil { - for i, v := range *s.Classes { - implID, err := extractImplID(*v.Class) - if err != nil { - return nil, fmt.Errorf("creating lookup key for class[%d]: %w", i, err) - } - - keys = append(keys, arm.RefValLookupKey(SchemeName, tenantID, implID)) - } - } - case coserv.ArtifactTypeTrustAnchors: - s := q.Query.EnvironmentSelector - - if s.Instances != nil { - for i, v := range *s.Instances { - instID, err := extractInstID(*v.Instance) - if err != nil { - return nil, fmt.Errorf("creating lookup key for instance[%d]: %w", i, err) - } - - keys = append(keys, arm.TaCoservLookupKey(SchemeName, tenantID, instID)) - } - } - case coserv.ArtifactTypeEndorsedValues: - return nil, errors.New("CCA does not implement endorsed value queries") - } - - return keys, nil -} - -func extractImplID(c comid.Class) (string, error) { - if c.ClassID == nil { - return "", errors.New("missing class-id") - } - - implID, err := c.ClassID.GetImplID() - if err != nil { - return "", fmt.Errorf("could not extract implementation-id from class-id: %w", err) - } - - return implID.String(), nil -} - -func extractInstID(i comid.Instance) (string, error) { - instID, err := i.GetUEID() - if err != nil { - return "", fmt.Errorf("could not extract implementation-id from instance-id: %w", err) - } - - return base64.StdEncoding.EncodeToString(instID), nil -} diff --git a/scheme/arm-cca/store_handler_test.go b/scheme/arm-cca/store_handler_test.go deleted file mode 100644 index 4ccb6821..00000000 --- a/scheme/arm-cca/store_handler_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -var testNonce = []byte{ - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, - 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, -} - -func Test_GetTrustAnchorIDs_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/cca-token.cbor") - require.NoError(t, err) - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - - expectedTaID := []string{"ARM_CCA://1/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=/AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"} - - scheme := &StoreHandler{} - - taID, err := scheme.GetTrustAnchorIDs(&token) - require.NoError(t, err) - assert.Equal(t, expectedTaID, taID) -} - -func Test_SynthKeysFromTrustAnchor_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/platform/ta-endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "ARM_CCA://1/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=/Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromTrustAnchor("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) - -} - -func Test_SynthKeysFromRefValue_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/platform/refval-endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "ARM_CCA://1/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromRefValue("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) -} - -func Test_GetReferenceIDs_ok(t *testing.T) { - var ta []string - var claims map[string]interface{} - expectedRefValID := []string{ - "ARM_CCA://1/AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA=", - "ARM_CCA://1/Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - } - evidenceBytes, err := os.ReadFile("test/evidence/extracted-claims.json") - require.NoError(t, err) - err = json.Unmarshal(evidenceBytes, &claims) - require.NoError(t, err) - scheme := &StoreHandler{} - refValID, err := scheme.GetRefValueIDs("1", ta, claims) - require.NoError(t, err) - assert.Equal(t, expectedRefValID, refValID) -} diff --git a/scheme/arm-cca/test/corim/build-test-vectors.sh b/scheme/arm-cca/test/corim/build-test-vectors.sh deleted file mode 100755 index 16a64376..00000000 --- a/scheme/arm-cca/test/corim/build-test-vectors.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -set -eu -set -o pipefail - -THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -GEN_CORIM="$THIS_DIR/../../../common/scripts/gen-corim" - -SUBATTESTERS=( - cca_platform - cca_realm -) - -CORIM_REALM_TEMPLATES=( - corimCcaRealm -) - -COMID_REALM_TEMPLATES=( - comidCcaRealm - comidCcaRealmNoClass - comidCcaRealmNoInstance - comidCcaRealmInvalidInstance - comidCcaRealmInvalidClass -) - -CORIM_PLATFORM_TEMPLATES=( - corimCca - corimCcaNoProfile -) - -COMID_PLATFORM_TEMPLATES=( - comidCcaRefValOne - comidCcaRefValFour -) - -# function to generate test vectors for the supplied CCA Platform or Realm -# $1 passed argument whose templates needs to be constructed -generate_templates() { - local sub_at=$1 - - echo "generating templates for subattester $sub_at" - - if [ "$sub_at" == "cca_platform" ]; then - COMID_TEMPLATES=("${COMID_PLATFORM_TEMPLATES[@]}") - CORIM_TEMPLATES=("${CORIM_PLATFORM_TEMPLATES[@]}") - else - COMID_TEMPLATES=("${COMID_REALM_TEMPLATES[@]}") - CORIM_TEMPLATES=("${CORIM_REALM_TEMPLATES[@]}") - fi - - for corim in "${CORIM_TEMPLATES[@]}" - do - for comid in "${COMID_TEMPLATES[@]}" - do - "$GEN_CORIM" "$THIS_DIR" "$comid" "$corim" "unsigned" - done - done - -} - -for at in "${SUBATTESTERS[@]}" -do - generate_templates "$at" -done - -echo "done" diff --git a/scheme/arm-cca/test/corim/compile-endorsements.sh b/scheme/arm-cca/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..1eb9c47f --- /dev/null +++ b/scheme/arm-cca/test/corim/compile-endorsements.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/platform-corims.yaml" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/realm-corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p arm_cca "$THIS_DIR"/corim-*.cbor diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-no-class.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-no-class.cbor new file mode 100644 index 0000000000000000000000000000000000000000..ce04c1a304b8235b0920a3503659da9e3266057b GIT binary patch literal 351 zcmcb~_;m?Gg{lD*=z?enk(``p24=zJj2IhlGX9GAxrlKgLx5Q>7guD5>)VzNeXS7x zBqx@I%#BS88E-PFMJO^d5de)hnY1c4>VklitGlP4LO`gKkEgSOw`(L=kjvLCyWF)r z(!)DH%CjoVz}Yb{(i6&daSTj$2~2l%_4Rgg4)OC$_6`kp$;>n~tPCzTHZ?NKbcwQX zP2)V2&wHFM7^^C;JM4>yX6N(?J0 zu1Zgj@GQ5rL2PP2x;^Gv2L)OMc3K0>J$k5odkYORiO{Rzl1qK43aS;PM<3gs!CdLQ_b~aWPW+p}kem-6vZZ1v^aWPR5 zVIe^Qc{y1bX(>qw<_d|7l9B=|ef`9uT)pJ{Tz#O+^oxsA^bJ{o<`jgb7A0mD=jSN| O6y;~7CYLZZG6Dc>oH8E( literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-digests.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-digests.cbor new file mode 100644 index 0000000000000000000000000000000000000000..39356b9137d5ddbef1f5f82b387c9baaed59109f GIT binary patch literal 232 zcmcb~_;m?Gg{lD*=z?enk(``p24=zJEEyYbGX9EaTEw`JA;5X}<9fYBZ{u~BgU^3- z>K0>J$k5odkYORiO{Rzl1qK43aS>2mqw#)T|5nGBp6nV6X?Br-}$3as??6N_^7lJj%*fsWNL gE>6)mWCa>s5SCh$m|2{krw~w-pOu@~ literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-mkey.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-mkey.cbor new file mode 100644 index 0000000000000000000000000000000000000000..02fb97e273862a6b351547a5fdfd00fc1c20d19b GIT binary patch literal 211 zcmcb~_;m?Gg{lD*=z?enk(``p24=zJ%o!VRGX9FlUBtMMA;5X}<9fYBZ{u~BgU^3- z>K0>J$k5odkYORiO{Rzl1qK43aUtVErp6}52nBXFRu*O^Mh1R9ULI~PP7ZM~Q4wJw zK>>L=Ss7_5NeSi(iHwqx0xNy}#G+iiyXBAA&+`52`|~4Bc67??0k{c8&@B&Bt#({OzZAAK!g?9|YgM`-;4LdjF^34=?Y( zA|F1z-#mWz&+lIaa)P9P$8eS-@e%_Z?oEqmk|cyH!$7DMV3r^#Bo-6^Xj~{T_C>Iz zWXqZyWNNVQ0X4H`D2Gxc0pDdIkQfA-OewM;hDCEJn@XT(3<9(GmEqH_dJUi{+A{zL zHE~>c7T5?ZbPs}2V=!-uh<1v6?-Bd^vu2JnV}`6}ngTb=p1X3c1|ps+B4kr|X0c3lt(IoZkqFIkSDn?i{!^#3>6;GupR$IeW|=cryg5=? zaO0CM8{xf0Z3yTQy0s_n7}Y087i_U=hp zb*Qo_R9IH<`|W+Z*B{p<0XTbZ!r4{aJpj$lpm#SVPzMU@mm9T<%LgL%YL}wwWfaC? z(_e77?hIoL)!7ktm8N)c?9dq6M>~n?tHi!eG;x>9_TnE2GDEEeNw<}&Jxcu~IQ{Wn zENJESyFwU*1Fo|}!?|~9os=}z7D~#T!7m7wKiD&mNrk87`5C$2-&y)<4^MY+`P_!u90~IDA-9BvlV6+~>T^tB+vDsBS;0T>&ZO(*( zo;ETlT|%hIS{mf?*kmG|S67ogcP$`nK9^A@#X3P>5udg?seByWv(EQv+cj3%Zc$*m z`*5VqF+St9gL2iw*$m9kox$copR#+&GRaY(c%nxZQLr)xHjj2X7uP0`g|M21t3@?& zb-9zePMPHqYL~E1lWW6Wv79nBrD-L5f1Qr`1!+}{fioqm@Y(G8S)?0F9*3n_?XfTQ z9qINRb+E!iJCH;{odVIoFX8okFV|SWZ4yK7^WoSeam>(MU5V%<7C<(Ir9YDsW|B+M zTbvKj6DgGPW>%2<<$`&l@(YpGCZZRj7h{VYkM;7J7dL#w%Dv>p4z2#X$$KuZ}dfe;uw& zoXu5Zxmi7cThB}aqWC42iEuqu)IBDw^@%eqs`h2#n^Q>8H+37;kw4zEn!EoDnR~dE z$1l)DzDC`zK^OUg=l`cJ*ge^Af=p@+$dIhr-9@sg+v9rXmu*Gh_IfnfajznzUGTNW z&{qp137Qa029OcywilX|&DcM&M4t=7c-oJ1y*rw@l6!Y_jb)dw@BJ7Zk#im$wx?mD zwAwGA9mvJry6d&&Ldl9R zQ$~+7fx0SbeszYjZj+{@fTw7|31);nXxlBsLt|Iq@R&6izHKfELME0N;T0rgQP`)N zq9n7$*Z>Hk>a4&n*fhA({6I$Awqi?RLemQG2cc^QoG|rDMkbgvj=NddNbL3jC3iFp z15)RPwLQ*~XHiUBK=v`g1~Noj->%!pj$J9NiDi2DI*sfVKHSk~e@RywWB7P0uH9p| zYGwydbml$Uaeq?x1D!NMT38zEBt_>%707pSexg_v$vQI)Q;jzhu`HgKRP~5NK`v6} zYIcCs8fWIDY{cgU6;~~t-QDG)L(oSa*`FlISdi?(2f1+(FO}7DiN)pt?g)FG_u>fz5np?U&D0^vj6}9 literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-instance.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-instance.cbor new file mode 100644 index 0000000000000000000000000000000000000000..7f3df6bd73df1fa3dd50da9a8e315daba066cfe6 GIT binary patch literal 392 zcmcb~_;m?Gg{lD*=z?enk(``p24=zJOc)z)GX9EWR9wWkkRiYHJj5nDKA`}^!2!O_$Oj;EibwR+%)!oxiAt2Pr$J1HC z+cgp_$mQ#nUG7>Q>EWFp`g%J#hxmCWdxr+QWM&!~ zRt6Uvn;MyAxgR&)EanP{jFOT9D}DXMqFlY?{9JutVCoka gr|289HZEc)2um$W%q-5&QwS)^&q_@$VQORq07yb&o&W#< literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-no-instance.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-no-instance.cbor new file mode 100644 index 0000000000000000000000000000000000000000..ea2636df3bcb2b4f2160687ff43f7a61516e4fdd GIT binary patch literal 352 zcmcb~_;m?Gg{lD*=z?enk(``p24=zJj2RnmGX9GAwTN*cLx5Q>7guD5>)VzNeXS7x zBqx@I%#BS885T0!WQvGTU?2b*Z!&3BY}5q-Cs%h*KZSr$Cm&B|1#j0#uppPOTXwl? zd8CJTew1fbmVvWlV5BFM?cx}i>=Kyn=<4h3lklGX9EWJhzB(Awz)k?#K0diQdNRE(f3g z=+rI7vXG&%X(7WxhMP+R$m;^&#{9UAPCnQ3TP8C+~^ zYGjt_5@q4Yl^K$69#U%N9pG44X6|C19&8j*;N_MSmFZamRF-S0Z5f(s=AKvPQLgVE zZWI-j7*^z{>qa`lq)bM=84M8CK=Mc8kjf}2DX`MlPb|vSOU}>L2PPH$qSVBkTzx~<#zhPTVW~xl TnZ@~e3IRp=S*gh-OpS~HlV+!9 literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-instance.cbor b/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-instance.cbor new file mode 100644 index 0000000000000000000000000000000000000000..e0ef1b84643cc6d5b2bcc253325e5bca720aaf82 GIT binary patch literal 617 zcmcb~_;m?Gg{lD*=z?enk(``p0%pPFj2RnmGX9EWVpznukRiZ%_v3oKL~rADmxIrL zbm|skS;)}Xw2)yT!%e1$2n7ZLpm8DNB9@y>1`!U9E|fvOrO8E^xs6R65f082f|R1v zTm!0^WJooWjHqUkF;z@ru8_(oDJihh*H0|U)l1IL)d!{({i4*woLqfF*2YB)1!1X0 UiJ8Uuc?tnV`B|ySB}|Qs0Iz&OZg9ry_3PIyS#)T|klN?5%K literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-raw-value.cbor b/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-raw-value.cbor new file mode 100644 index 0000000000000000000000000000000000000000..3964860a2fe9a93d104731afbdc3156712690d60 GIT binary patch literal 577 zcmcb~_;m?Gg{lD*=z?enk(``p0%pPFOc@(*GX9EWys?OJAwz)k?#K0diQdNRE(f3g z=+rI7vXG&%X(8iHCW8nEX9_{%LdJ!BOOuN-a~qpDC^s&pC^grBY9<*{%_JkLnPf~A zlb9={GD=Dctn~F0i*ogn^Kh15GX9EWl3T>MkRiZ%_v3oKL~rADmxIrL zbm|skS;)}Xw2<*8lR<=oGligWA>$$zut|^z{>qa`lq)bM=8KNxvvHF(+5wkhO6ULqS+-QDSCsex5== NQGQlxatTu-BLHhQw=Mtx literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-no-class.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-no-class.json new file mode 100644 index 00000000..63d1647d --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-no-class.json @@ -0,0 +1,24 @@ +{ + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "instance": { + "type": "ueid", + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----" + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-instance.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-instance.json new file mode 100644 index 00000000..948078bb --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-instance.json @@ -0,0 +1,98 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + }, + "instance": { + "type": "ueid", + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + } + }, + "measurements": [ + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "BL", + "version": "3.4.2", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "M1", + "version": "1.2.0", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "M2", + "version": "1.2.3", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "M3", + "version": "1.0.0", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "cca.platform-config-id", + "value": "cfg v1.0.0" + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AQID" + } + } + } + ] + } + ] + } + } diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-mkey.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-mkey.json new file mode 100644 index 00000000..ade7c3de --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-mkey.json @@ -0,0 +1,33 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + } + }, + "measurements": [ + { + "key": { + "type": "uint", + "value": 7 + }, + "value": { + "digests": [ + "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + } + ] + } + ] + } + } diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-digests.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-digests.json new file mode 100644 index 00000000..3f9d4297 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-digests.json @@ -0,0 +1,38 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + } + }, + "measurements": [ + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "BL", + "version": "3.4.2", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AQID" + } + } + } + ] + } + ] + } + } diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-mkey.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-mkey.json new file mode 100644 index 00000000..944d3a3f --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-mkey.json @@ -0,0 +1,29 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + } + }, + "measurements": [ + { + "value": { + "digests": [ + "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + } + ] + } + ] + } +} diff --git a/scheme/parsec-cca/test/corim/src/ComidParsecCcaRefValOne.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-raw-value.json similarity index 51% rename from scheme/parsec-cca/test/corim/src/ComidParsecCcaRefValOne.json rename to scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-raw-value.json index c24561ee..c67b93d8 100644 --- a/scheme/parsec-cca/test/corim/src/ComidParsecCcaRefValOne.json +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-refval-no-raw-value.json @@ -1,20 +1,8 @@ { - "lang": "en-GB", "tag-identity": { "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { @@ -22,10 +10,8 @@ "class": { "id": { "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } } }, "measurements": [ @@ -35,14 +21,13 @@ "value": "cfg v1.0.0" }, "value": { - "raw-value": { - "type": "bytes", - "value": "cmF3dmFsdWUKcmF3dmFsdWUK" - } + "digests": [ + "sha-256:CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] } } ] } ] } - } \ No newline at end of file + } diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-cert.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-cert.json new file mode 100644 index 00000000..fc13de01 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-cert.json @@ -0,0 +1,30 @@ +{ + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + }, + "instance": { + "type": "ueid", + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert", + "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-instance.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-instance.json new file mode 100644 index 00000000..0b384f3a --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-instance.json @@ -0,0 +1,30 @@ +{ + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + }, + "instance": { + "type": "bytes", + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----" + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-no-instance.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-no-instance.json new file mode 100644 index 00000000..2ab314a7 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-bad-ta-no-instance.json @@ -0,0 +1,26 @@ +{ + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + } + }, + "verification-keys": [ + { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----" + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-refval.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-refval.json new file mode 100644 index 00000000..3aabfb34 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-refval.json @@ -0,0 +1,94 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + } + }, + "measurements": [ + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "BL", + "version": "3.4.2", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "M1", + "version": "1.2.0", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "M2", + "version": "1.2.3", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "M3", + "version": "1.0.0", + "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + } + }, + "value": { + "digests": [ + "sha-256:EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" + ] + } + }, + { + "key": { + "type": "cca.platform-config-id", + "value": "cfg v1.0.0" + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AQID" + } + } + } + ] + } + ] + } + } diff --git a/scheme/arm-cca/test/corim/src/comid-cca-platform-ta.json b/scheme/arm-cca/test/corim/src/comid-cca-platform-ta.json new file mode 100644 index 00000000..03f82130 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-platform-ta.json @@ -0,0 +1,30 @@ +{ + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + }, + "instance": { + "type": "ueid", + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----" + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comidCcaRealmNoInstance.json b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-instance.json similarity index 52% rename from scheme/arm-cca/test/corim/src/comidCcaRealmNoInstance.json rename to scheme/arm-cca/test/corim/src/comid-cca-realm-bad-instance.json index c849be77..9f11cf2b 100644 --- a/scheme/arm-cca/test/corim/src/comidCcaRealmNoInstance.json +++ b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-instance.json @@ -1,64 +1,53 @@ { - "lang": "en-GB", "tag-identity": { "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "Workload Client Ltd.", - "regid": "https://workloadclient.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { "environment": { - "class": { - "id": { - "type": "uuid", - "value": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C" - }, - "vendor": "Workload Client Ltd" + "instance": { + "type": "ueid", + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" } }, "measurements": [ { "value": { + "raw-value": { + "type": "bytes", + "value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==" + }, "integrity-registers": { "rim": { "key-type": "text", "value": [ - "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem0": { "key-type": "text", "value": [ - "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem1": { "key-type": "text", "value": [ - "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem2": { "key-type": "text", "value": [ - "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem3": { "key-type": "text", "value": [ - "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] } } @@ -68,4 +57,4 @@ } ] } -} \ No newline at end of file +} diff --git a/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-instance.json b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-instance.json new file mode 100644 index 00000000..6f1bf82d --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-instance.json @@ -0,0 +1,62 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } + } + }, + "measurements": [ + { + "value": { + "raw-value": { + "type": "bytes", + "value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==" + }, + "integrity-registers": { + "rim": { + "key-type": "text", + "value": [ + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + ] + }, + "rem0": { + "key-type": "text", + "value": [ + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + ] + }, + "rem1": { + "key-type": "text", + "value": [ + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + ] + }, + "rem2": { + "key-type": "text", + "value": [ + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + ] + }, + "rem3": { + "key-type": "text", + "value": [ + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + ] + } + } + } + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-integ-regs.json b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-integ-regs.json new file mode 100644 index 00000000..0b698313 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-integ-regs.json @@ -0,0 +1,28 @@ +{ + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", + "version": 0 + }, + "triples": { + "reference-values": [ + { + "environment": { + "instance": { + "type": "bytes", + "value": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + } + }, + "measurements": [ + { + "value": { + "raw-value": { + "type": "bytes", + "value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==" + } + } + } + ] + } + ] + } +} diff --git a/scheme/arm-cca/test/corim/src/comidCcaRealmNoClass.json b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-raw-value.json similarity index 57% rename from scheme/arm-cca/test/corim/src/comidCcaRealmNoClass.json rename to scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-raw-value.json index 3d5bcf60..56c66fb9 100644 --- a/scheme/arm-cca/test/corim/src/comidCcaRealmNoClass.json +++ b/scheme/arm-cca/test/corim/src/comid-cca-realm-bad-no-raw-value.json @@ -1,27 +1,15 @@ { - "lang": "en-GB", "tag-identity": { "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "Workload Client Ltd.", - "regid": "https://workloadclient.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { "environment": { "instance": { "type": "bytes", - "value": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + "value": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" } }, "measurements": [ @@ -31,31 +19,31 @@ "rim": { "key-type": "text", "value": [ - "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem0": { "key-type": "text", "value": [ - "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem1": { "key-type": "text", "value": [ - "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem2": { "key-type": "text", "value": [ - "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem3": { "key-type": "text", "value": [ - "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] } } @@ -65,4 +53,4 @@ } ] } -} \ No newline at end of file +} diff --git a/scheme/arm-cca/test/corim/src/comidCcaRealmInvalidClass.json b/scheme/arm-cca/test/corim/src/comid-cca-realm-refval.json similarity index 52% rename from scheme/arm-cca/test/corim/src/comidCcaRealmInvalidClass.json rename to scheme/arm-cca/test/corim/src/comid-cca-realm-refval.json index acd2ea34..e3a37275 100644 --- a/scheme/arm-cca/test/corim/src/comidCcaRealmInvalidClass.json +++ b/scheme/arm-cca/test/corim/src/comid-cca-realm-refval.json @@ -1,34 +1,15 @@ { - "lang": "en-GB", "tag-identity": { "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "Workload Client Ltd.", - "regid": "https://workloadclient.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { "environment": { - "class": { - "id": { - "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME" - }, "instance": { "type": "bytes", - "value": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + "value": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" } }, "measurements": [ @@ -36,37 +17,37 @@ "value": { "raw-value": { "type": "bytes", - "value": "5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82j/dOYjR6gk3stnqE5SJNdQ==" + "value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==" }, "integrity-registers": { "rim": { "key-type": "text", "value": [ - "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem0": { "key-type": "text", "value": [ - "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem1": { "key-type": "text", "value": [ - "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem2": { "key-type": "text", "value": [ - "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] }, "rem3": { "key-type": "text", "value": [ - "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" + "sha-512;Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" ] } } @@ -76,4 +57,4 @@ } ] } -} \ No newline at end of file +} diff --git a/scheme/arm-cca/test/corim/src/comidCcaRealm.json b/scheme/arm-cca/test/corim/src/comidCcaRealm.json deleted file mode 100644 index cd59b035..00000000 --- a/scheme/arm-cca/test/corim/src/comidCcaRealm.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "lang": "en-GB", - "tag-identity": { - "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", - "version": 0 - }, - "entities": [ - { - "name": "Workload Client Ltd.", - "regid": "https://workloadclient.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], - "triples": { - "reference-values": [ - { - "environment": { - "class": { - "id": { - "type": "uuid", - "value": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C" - }, - "vendor": "Workload Client Ltd" - }, - "instance": { - "type": "bytes", - "value": "QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" - } - }, - "measurements": [ - { - "value": { - "raw-value": { - "type": "bytes", - "value": "5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXXkW3L1wMC1cttNjTq36X82j/dOYjR6gk3stnqE5SJNdQ==" - }, - "integrity-registers": { - "rim": { - "key-type": "text", - "value": [ - "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" - ] - }, - "rem0": { - "key-type": "text", - "value": [ - "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - }, - "rem1": { - "key-type": "text", - "value": [ - "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - }, - "rem2": { - "key-type": "text", - "value": [ - "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - }, - "rem3": { - "key-type": "text", - "value": [ - "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - } - } - } - } - ] - } - ] - } -} \ No newline at end of file diff --git a/scheme/arm-cca/test/corim/src/comidCcaRealmInvalidInstance.json b/scheme/arm-cca/test/corim/src/comidCcaRealmInvalidInstance.json deleted file mode 100644 index d59681fa..00000000 --- a/scheme/arm-cca/test/corim/src/comidCcaRealmInvalidInstance.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "lang": "en-GB", - "tag-identity": { - "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", - "version": 0 - }, - "entities": [ - { - "name": "Workload Client Ltd.", - "regid": "https://workloadclient.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], - "triples": { - "reference-values": [ - { - "environment": { - "class": { - "id": { - "type": "uuid", - "value": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C" - }, - "vendor": "Workload Client Ltd" - }, - "instance": { - "type": "ueid", - "value": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } - }, - "measurements": [ - { - "value": { - "integrity-registers": { - "rim": { - "key-type": "text", - "value": [ - "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" - ] - }, - "rem0": { - "key-type": "text", - "value": [ - "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - }, - "rem1": { - "key-type": "text", - "value": [ - "sha-384;JQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - }, - "rem2": { - "key-type": "text", - "value": [ - "sha-384;MQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - }, - "rem3": { - "key-type": "text", - "value": [ - "sha-384;NQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - } - } - } - } - ] - } - ] - } -} \ No newline at end of file diff --git a/scheme/arm-cca/test/corim/src/comidCcaRefValOne.json b/scheme/arm-cca/test/corim/src/comidCcaRefValOne.json deleted file mode 100644 index 0871e7ea..00000000 --- a/scheme/arm-cca/test/corim/src/comidCcaRefValOne.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "lang": "en-GB", - "tag-identity": { - "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", - "version": 0 - }, - "profiles": "http://arm.com/cca/ssd/1.0", - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], - "triples": { - "reference-values": [ - { - "environment": { - "class": { - "id": { - "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" - } - }, - "measurements": [ - { - "key": { - "type": "cca.platform-config-id", - "value": "any-label" - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "cmF3dmFsdWUKcmF3dmFsdWUK" - } - } - } - ] - } - ] - } -} diff --git a/scheme/arm-cca/test/corim/src/corim-cca-platform.json b/scheme/arm-cca/test/corim/src/corim-cca-platform.json new file mode 100644 index 00000000..f1bac236 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/corim-cca-platform.json @@ -0,0 +1,12 @@ +{ + "corim-id": "00000000-0000-0000-cca6-000000000000", + "profile": "http://arm.com/cca/ssd/1", + "entities": [ + { + "name": "Veraison Project", + "roles": [ + "manifestCreator" + ] + } + ] +} diff --git a/scheme/arm-cca/test/corim/src/corim-cca-realm.json b/scheme/arm-cca/test/corim/src/corim-cca-realm.json new file mode 100644 index 00000000..514c8363 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/corim-cca-realm.json @@ -0,0 +1,12 @@ +{ + "corim-id": "00000000-0000-0000-cca4-000000000000", + "profile": "http://arm.com/cca/realm/1", + "entities": [ + { + "name": "Veraison Project", + "roles": [ + "manifestCreator" + ] + } + ] +} diff --git a/scheme/arm-cca/test/corim/src/corimCca.json b/scheme/arm-cca/test/corim/src/corimCca.json deleted file mode 100644 index cbebc13b..00000000 --- a/scheme/arm-cca/test/corim/src/corimCca.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", - "dependent-rims": [ - { - "href": "https://parent.example/rims/ccb3aa85-61b4-40f1-848e-02ad6e8a254b", - "thumbprint": "sha-256:5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" - } - ], - "profile": "http://arm.com/cca/ssd/1", - "validity": { - "not-before": "2021-12-31T00:00:00Z", - "not-after": "2025-12-31T00:00:00Z" - }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "acme.example", - "roles": [ - "manifestCreator" - ] - } - ] -} diff --git a/scheme/arm-cca/test/corim/src/corimCcaNoProfile.json b/scheme/arm-cca/test/corim/src/corimCcaNoProfile.json deleted file mode 100644 index b0650f9e..00000000 --- a/scheme/arm-cca/test/corim/src/corimCcaNoProfile.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", - "dependent-rims": [ - { - "href": "https://parent.example/rims/ccb3aa85-61b4-40f1-848e-02ad6e8a254b", - "thumbprint": "sha-256:5Fty9cDAtXLbTY06t+l/No/3TmI0eoJN7LZ6hOUiTXU=" - } - ], - "validity": { - "not-before": "2021-12-31T00:00:00Z", - "not-after": "2025-12-31T00:00:00Z" - }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "acme.example", - "roles": [ - "manifestCreator" - ] - } - ] -} diff --git a/scheme/arm-cca/test/corim/src/corimCcaRealm.json b/scheme/arm-cca/test/corim/src/corimCcaRealm.json deleted file mode 100644 index d57492bd..00000000 --- a/scheme/arm-cca/test/corim/src/corimCcaRealm.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", - "profile": "http://arm.com/cca/realm/1", - "validity": { - "not-before": "2021-12-31T00:00:00Z", - "not-after": "2025-12-31T00:00:00Z" - }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "acme.example", - "roles": [ - "manifestCreator" - ] - } - ] -} diff --git a/scheme/arm-cca/test/corim/src/platform-corims.yaml b/scheme/arm-cca/test/corim/src/platform-corims.yaml new file mode 100644 index 00000000..a274c241 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/platform-corims.yaml @@ -0,0 +1,25 @@ +corim: corim-cca-platform +outdir: .. +workdir: ../__build_platform +comids: + cca-platform-valid: + - comid-cca-platform-refval + - comid-cca-platform-ta + cca-platform-bad-no-class: + - comid-cca-platform-bad-no-class + cca-platform-bad-ta-no-instance: + - comid-cca-platform-bad-ta-no-instance + cca-platform-bad-ta-instance: + - comid-cca-platform-bad-ta-instance + cca-platform-bad-ta-cert: + - comid-cca-platform-bad-ta-cert + cca-platform-bad-refval-instance: + - comid-cca-platform-bad-refval-instance + cca-platform-bad-refval-no-mkey: + - comid-cca-platform-bad-refval-no-mkey + cca-platform-bad-refval-mkey: + - comid-cca-platform-bad-refval-mkey + cca-platform-bad-refval-no-digests: + - comid-cca-platform-bad-refval-no-digests + cca-platform-bad-refval-no-raw-value: + - comid-cca-platform-bad-refval-no-raw-value diff --git a/scheme/arm-cca/test/corim/src/realm-corims.yaml b/scheme/arm-cca/test/corim/src/realm-corims.yaml new file mode 100644 index 00000000..eb30ff90 --- /dev/null +++ b/scheme/arm-cca/test/corim/src/realm-corims.yaml @@ -0,0 +1,14 @@ +corim: corim-cca-realm +outdir: .. +workdir: ../__build_realm +comids: + cca-realm-valid: + - comid-cca-realm-refval + cca-realm-bad-instance: + - comid-cca-realm-bad-instance + cca-realm-bad-no-instance: + - comid-cca-realm-bad-no-instance + cca-realm-bad-no-integ-regs: + - comid-cca-realm-bad-no-integ-regs + cca-realm-bad-no-raw-value: + - comid-cca-realm-bad-no-raw-value diff --git a/scheme/arm-cca/test/corim/submit-arm-cca-endorsements.sh b/scheme/arm-cca/test/corim/submit-arm-cca-endorsements.sh new file mode 100755 index 00000000..fea48019 --- /dev/null +++ b/scheme/arm-cca/test/corim/submit-arm-cca-endorsements.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +cocli corim submit -i --corim-file corim-cca-platform-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="http://arm.com/cca/ssd/1"' --auth=none +cocli corim submit -i --corim-file corim-cca-realm-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="http://arm.com/cca/realm/1"' --auth=none + diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValFour.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValFour.cbor deleted file mode 100644 index a935043845485eed0bb02245693fbc389737a945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 671 zcmcb~_;ndWKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9A8BZ)>NKMVtb$4Q1$PnPX`*FQq zqPOw7%faVAI(3UNH7;hzbaeK0Rq!cE(PO-!P?AwnQc!HAub-Hlo2r*uk(gVMlgiZ0 zz{te1kfE_@A;V&Zn@kZA3Lt6SOps)5YFxtKA@$%iG?NY7BufHgv4&2GWtPi`p|u?E>ZIVYtO^>C5pI-Bgj^C}9z zKfST*MK6c{q5fJ|k|3d&DR2`bIY zOD$?#1k@RonV46po0FK7n!~t|ROmsr0NNKMVtb$4Q1$PnPX`*FQq zqPOw7%faVAI(3UNH7;hzbaeK0Rq!cE(PO-!P?AwnQc!HAub-Hlo2r*uk(gVMlgiZ0 zz{te1kfE_@A;V&Zn@kZA3Lt6SOps)5YFxtKA@$%iG?NY7BufHgv4&2GWtPi`p|u?E>ZIVYtO^>C5pI-Bgj^C}9z zKfST*MK6c{q5fJ|k|3d&DR2`bIY zOD$?#1k@RonV46po0FK7n!~t|ROmsr0N2!low~)C8W%H^gy$D!=j11*C^+Y2rskC>_>`pRG2T$9kjp43DJZtm*Dr@E zNCwO6rB)>77UZNdH8U_Wu`Fb0Y+A&yh~b86z*%{|P_>_KygP4v|NF48qK2^;i^+^P znG7NfoLaVK`Ybze>AZXAf}K$(m|_}xpDMGMc|Sj^*|_P_+heVpmDKAFMMzFl5x#M9 z)4{Ke3mF%&fOI-Mi7xtj;K0_R+rGV4+h5k3^?&zEGO23veY35q<*AZyDIs~jrO8E^ zxs6Tiq&p&|C^gprtW%MF_w&R*OLeCTX9eX*LJz=yiJyEo4uEbuKpJ2 z^EobR-qI*$UAC?YkWNFePE|5=8i92hlA+TWtkaZ4oy-+dpqK|nd}2|qUUGh}esXf6 xeo<;-POiQo%OZw@Qi2!low~)C8W%H^gy$D!=j11*C^+Y2rskC>_>`pRG2T$9kjp43DJZtm*Dr@E zNCwO6rB)>77UZNdH8U_Wu`Fb0Y+A&yh~XwvM1(?Oa&D?_CP*?DXi#EFW`3S-W{R!> z6c{q5I6C{fGTvk|h%j(!*_!FI?7*e-?wt#EMx9`aY3zNf%wp#K{H$iq_wzcwypT*Ly>>F^}F=<9(4TZ?Y{_F8R!S#Q?=-7m?cs>%1wwyKt= zO1`Cp(9~k$E zMY(#(`MLVZ$%*%^6rO8E^xs6Ti z5e7~zTQhx@9k_Jfy>r3Ns1r;vjlEBmSO|vIJxQI z*Oa2vTm!I9MfTm#6aOsLohqCq9CEwL_iDAY+CE;}<+AfOS+;HVUM9NwTcFS9xTtwc zqnLHsx+*|A4Z%89$(2^dF-MY(#(`MLVZ$%*!=cdA=vyl-15H#+v diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor deleted file mode 100644 index 0e4c85cfe551bab60416618453196dc5c0c88b2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 556 zcmcb~_;o2mKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9A84oOBNKMVtb$4Q1$PnPX`*FQq zqPOw7%faVAI(3UNH7;f-3C}Oe&dE3E}eJpT(C3h1XE07?^9(K zGwQ73bS6euEq@sL=QtCyUgtDl^ls9%(tn3Jn-$g+sxpj6^H h4+h4AQkfy?4XnTj&2)73b%n)ZPGWLyDm=;>839fd=u-dy diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor deleted file mode 100644 index 4d84201fbebd72833cb2767fcd27bbaf58495ded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 545 zcmcb~_;o2mKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9A8MiKBNKMVtb$4Q1$PnPX`*FQq zqPOw7%faVAI(3UNH7;f-3C}Oe&dEnp~8b+t|b&Vc^uVHPdI=flKGzI~VMXI>8jv*!xtO#mxKpSE_H~6tT~1g3mMfGL^7$blw{LcXoEv4GwnE zH`FuGGvJC)c*=O(`}$n2Nv7rzag}n11BC1vS4|I){UPMSq-fG~G+2@|CPIOM0FY#4 zh)`r?A^;>g6P+2Em?b%*B@GxPIpbTFFeW+qFhwY^v$3);Gchvo^YQXBSj|x<;mE5e^SF%((rOU1CYo`s9Flf7W(OABtkhQC{&WQcrx3(8=y# z=jZG0I`m9e`N4Si@|MSIq@NtT^T;UKU2m!JT*rp%SM4R&T#RITcd5l?A)|#7Fy%F_ z0H?f?#B?iYvePj#Ffz6(N=?kkRfeWKhkTW5JCmbyy7x!CTmvt=h8QS>!Pg%yRR3&dvva>MO7)n;O$q}xBEK(uYd3|d#~H0 zf=}$zj(F_sUGKI$;m0WWHW_3h@W0LBcrYO~U zT6$;web#KV<=N_6$-l4eyX(@m#;Gf84#Zq>U2w0qP tChDof`mV+555Io?W0kj}=W3!rQ%HZ7arxG7bMCRWx>+VaG2imzH2^CSkQD#` literal 0 HcmV?d00001 diff --git a/scheme/arm-cca/test/evidence/cca-token.cbor b/scheme/arm-cca/test/evidence/cca-token.cbor deleted file mode 100644 index c47dab85987941d8a2307fdd03f7fcf1d2ea9c15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1404 zcmcb~*uO|}&8bMHm6uwa7c#0Xh-8XgDapuLA(K&3QedU8pIDTumzVRWXTTNV!1`=!hs&`AXC*BZGI#ym@MKDwmerjfe;%EwY$F~KQ zZ*eJ9b*F{qaVdSA_ssi_e&DZ!FztY@NU z#7bBtTShoh0HnQv-tKv8OhXTTE1Bws_IJ=_HCG1N2CGa$kqkcmb>6ZwfU z(U?dRje#Z#6Ja7SW{EISk~5(~50pBJfytvRwJ0&OI6qG>wIVUMASYG7%uqi$BQYl@ zH7`9?wxd;bm3W4OB^DUH{GCWL>TyqANZY0;7jYwo^ z`hC%8<<`T~+UM^UHQ}8QFugDI_}rk%MZ5T>w)&et;<@zA-@0gP!S3tD?;f2iYf*js z)%ESZ&j0Hlyv*L~_Nd?!`?Mn-JA2o=El;^r;`Hp<+m;{aPKZByb8NY+mF@Fub!R2l zTmV~WYG@RZ5T&a#*H&(2$Yw#m^t|c#K|IYs(8+c%`I%7Y}kVxW(SDd%QtbY7dL#~|7m)8VvT*`YBi4_ JXN8buUjZTPha&(0 diff --git a/scheme/arm-cca/test/evidence/cca-token.json b/scheme/arm-cca/test/evidence/cca-token.json deleted file mode 100644 index 8ea00cc9..00000000 --- a/scheme/arm-cca/test/evidence/cca-token.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "cca-platform-token": { - "cca-platform-profile": "http://arm.com/CCA-SSD/1.0.0", - "cca-platform-implementation-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "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" - }, - "cca-realm-delegated-token": { - "cca-realm-challenge": "QUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQg==", - "cca-realm-personalization-value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==", - "cca-realm-initial-measurement": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "cca-realm-extensible-measurements": [ - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" - ], - "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" - } -} \ No newline at end of file diff --git a/scheme/arm-cca/test/evidence/compile-cca-evidence.sh b/scheme/arm-cca/test/evidence/compile-cca-evidence.sh new file mode 100755 index 00000000..37a036c6 --- /dev/null +++ b/scheme/arm-cca/test/evidence/compile-cca-evidence.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SRC_DIR="$THIS_DIR/src" + +evcli cca create --iak="$SRC_DIR/ec.p256.jwk" --rak="$SRC_DIR/ec.p384.jwk" \ + --claims="$SRC_DIR/cca-good.json" --token="$THIS_DIR/cca-good.cbor" diff --git a/scheme/arm-cca/test/evidence/extracted-claims.json b/scheme/arm-cca/test/evidence/extracted-claims.json deleted file mode 100644 index fb92a367..00000000 --- a/scheme/arm-cca/test/evidence/extracted-claims.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "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": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "cca-realm-extensible-measurements": [ - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" - ], - "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" - } -} \ No newline at end of file diff --git a/scheme/arm-cca/test/evidence/extracted.json b/scheme/arm-cca/test/evidence/extracted.json deleted file mode 100644 index 30d7e170..00000000 --- a/scheme/arm-cca/test/evidence/extracted.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "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": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "cca-realm-extensible-measurements": [ - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", - "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" - ], - "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" - } - }, - "trust-anchor-ids": ["CCA_SSD_PLATFORM://1/BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=/AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY"], - "reference-ids": ["CCA_SSD_PLATFORM://1/BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=/"], - "tenant-id": "1" -} diff --git a/scheme/arm-cca/test/evidence/src/cca-good.json b/scheme/arm-cca/test/evidence/src/cca-good.json new file mode 100644 index 00000000..6cc821c5 --- /dev/null +++ b/scheme/arm-cca/test/evidence/src/cca-good.json @@ -0,0 +1,52 @@ +{ + "cca-platform-token": { + "cca-platform-challenge": "5QHHS9edCpI1N1heeR7DUBI+gaqXUB34EkQCITSCxVM=", + "cca-platform-profile": "http://arm.com/CCA-SSD/1.0.0", + "cca-platform-implementation-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "cca-platform-instance-id": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC", + "cca-platform-config": "AQID", + "cca-platform-lifecycle": 12288, + "cca-platform-sw-components": [ + { + "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" + }, + "cca-realm-delegated-token": { + "cca-realm-challenge": "byTWuWNaLIu/WOkIuU4Ewb+zroDN6+gyQkV4SZ/jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA==", + "cca-realm-personalization-value": "QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==", + "cca-realm-initial-measurement": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", + "cca-realm-extensible-measurements": [ + "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", + "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", + "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==", + "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" + ], + "cca-realm-hash-algo-id": "sha-256", + "cca-realm-public-key": "pAECIAIhWDCC+9EyqbXDloefuxU0DZBQl45Vx51SeaK6DpWFTzfiDNL2TztytXC713Pu4s52hCUiWDDt9UXtvon/r+Dpa71G4nDyB5bESLmNr0anZNJ0Qubm7YT4zsgX5uzGpx06PefWfs0=", + "cca-realm-public-key-hash-algo-id": "sha-256" + } +} diff --git a/scheme/arm-cca/test/evidence/src/ec.p256.jwk b/scheme/arm-cca/test/evidence/src/ec.p256.jwk new file mode 100644 index 00000000..e3c07719 --- /dev/null +++ b/scheme/arm-cca/test/evidence/src/ec.p256.jwk @@ -0,0 +1,9 @@ +{ + "kty": "EC", + "crv": "P-256", + "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", + "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", + "d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE", + "use": "enc", + "kid": "1" +} diff --git a/scheme/arm-cca/test/evidence/src/ec.p384.jwk b/scheme/arm-cca/test/evidence/src/ec.p384.jwk new file mode 100644 index 00000000..cd97e3a4 --- /dev/null +++ b/scheme/arm-cca/test/evidence/src/ec.p384.jwk @@ -0,0 +1,8 @@ +{ + "kid": "example-rak", + "kty": "EC", + "crv": "P-384", + "x": "gvvRMqm1w5aHn7sVNA2QUJeOVcedUnmiug6VhU834gzS9k87crVwu9dz7uLOdoQl", + "y": "7fVF7b6J_6_g6Wu9RuJw8geWxEi5ja9Gp2TSdELm5u2E-M7IF-bsxqcdOj3n1n7N", + "d": "ODkwMTIzNDU2Nzg5MDEyMz7deMbyLt8g4cjcxozuIoygLLlAeoQ1AfM9TSvxkFHJ" +} \ No newline at end of file diff --git a/scheme/arm-cca/test/evidence/submit-arm-cca-evidence.sh b/scheme/arm-cca/test/evidence/submit-arm-cca-evidence.sh new file mode 100755 index 00000000..0f84dbf8 --- /dev/null +++ b/scheme/arm-cca/test/evidence/submit-arm-cca-evidence.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession?nonce=byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA== 2>/dev/null | grep "location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H 'content-type: application/eat-collection; profile="https://arm.com/CCA-SSD/1.0.0"' --data-binary @cca-good.cbor http://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/arm-cca/test/platform/endorsements.json b/scheme/arm-cca/test/platform/endorsements.json deleted file mode 100644 index 668c7519..00000000 --- a/scheme/arm-cca/test/platform/endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQID\"}}" -] diff --git a/scheme/arm-cca/test/platform/invalid-key-ta-endorsements.json b/scheme/arm-cca/test/platform/invalid-key-ta-endorsements.json deleted file mode 100644 index 1515bb30..00000000 --- a/scheme/arm-cca/test/platform/invalid-key-ta-endorsements.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scheme": "ARM_CCA", - "type": "VERIFICATION_KEY", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "iak-pub": "-----BEGIN PRIVATE KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgvvRMqm1w5aHn7sVNA2QUJeOVcedUnmiug6VhU834gzS9k87crVwu9dz7uLOdoQl7fVF7b6J/6/g6Wu9RuJw8geWxEi5ja9G\np2TSdELm5u2E+M7IF+bsxqcdOj3n1n7N\n-----END PRIVATE KEY-----", - "inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} diff --git a/scheme/arm-cca/test/platform/mismatch-cfg-endorsements.json b/scheme/arm-cca/test/platform/mismatch-cfg-endorsements.json deleted file mode 100644 index daf117b4..00000000 --- a/scheme/arm-cca/test/platform/mismatch-cfg-endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"ACID\"}}" -] diff --git a/scheme/arm-cca/test/platform/mismatch-refval-endorsements.json b/scheme/arm-cca/test/platform/mismatch-refval-endorsements.json deleted file mode 100644 index a67df936..00000000 --- a/scheme/arm-cca/test/platform/mismatch-refval-endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"AwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQID\"}}" -] diff --git a/scheme/arm-cca/test/platform/mult-endorsements.json b/scheme/arm-cca/test/platform/mult-endorsements.json deleted file mode 100644 index 60fc23d7..00000000 --- a/scheme/arm-cca/test/platform/mult-endorsements.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - "{\n\"scheme\":\"ARM_CCA\",\n\"type\":\"REFERENCE_VALUE\",\n\"subType\":\"platform.sw-component\",\n\"attributes\":{\n \"hw-model\":\"RoadRunner\",\n \"hw-vendor\":\"ACME\",\n \"impl-id\":\"76543210fedcba9817161514131211101f1e1d1c1b1a1918\",\n \"measurement-desc\":\"sha-256\",\n \"measurement-type\":\"BL\",\n \"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"version\":\"3.4.2\"\n }\n }", - "\n{\n \"scheme\":\"ARM_CCA\",\n \"type\":\"REFERENCE_VALUE\",\n\"subType\":\"platform.sw-component\",\n \"attributes\":{\n \"hw-model\":\"RoadRunner\",\n \"hw-vendor\":\"ACME\",\n \"impl-id\":\"76543210fedcba9817161514131211101f1e1d1c1b1a1918\",\n \"measurement-desc\":\"sha-256\",\n \"measurement-type\":\"M1\",\n \"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"version\":\"1.2.0\"}\n }\n ", - "\n {\n \"scheme\":\"ARM_CCA\",\n \"type\":\"REFERENCE_VALUE\",\n\"subType\":\"platform.sw-component\",\n, \"attributes\":{\n \"hw-model\":\"RoadRunner\",\n \"hw-vendor\":\"ACME\",\n \"impl-id\":\"76543210fedcba9817161514131211101f1e1d1c1b1a1918\",\n \"measurement-desc\":\"sha-256\",\n \"measurement-type\":\"M2\",\n \"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\n \"version\":\"1.2.3\"}\n }\n " -] \ No newline at end of file diff --git a/scheme/arm-cca/test/platform/refval-endorsements.json b/scheme/arm-cca/test/platform/refval-endorsements.json deleted file mode 100644 index bf3460bf..00000000 --- a/scheme/arm-cca/test/platform/refval-endorsements.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "scheme": "ARM_CCA", - "type": "REFERENCE_VALUE", - "subType": "platform.config", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "platform-config-label": "abcd", - "platform-config-id": "AQID" - } -} diff --git a/scheme/arm-cca/test/platform/ta-endorsements.json b/scheme/arm-cca/test/platform/ta-endorsements.json deleted file mode 100644 index fc9975d3..00000000 --- a/scheme/arm-cca/test/platform/ta-endorsements.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scheme": "ARM_CCA", - "type": "VERIFICATION_KEY", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} diff --git a/scheme/arm-cca/test/platform/ta-integ-endorsements.json b/scheme/arm-cca/test/platform/ta-integ-endorsements.json deleted file mode 100644 index 0027b84d..00000000 --- a/scheme/arm-cca/test/platform/ta-integ-endorsements.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scheme": "ARM_CCA", - "type": "VERIFICATION_KEY", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "76543210fedcba9817161514131211101f1e1d1c1b1a1918", - "iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} diff --git a/scheme/arm-cca/test/realm/match-endorsements.json b/scheme/arm-cca/test/realm/match-endorsements.json deleted file mode 100644 index 75332a7f..00000000 --- a/scheme/arm-cca/test/realm/match-endorsements.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQID\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"realm.reference-value\",\"attributes\":{\"realm-initial-measurement\":\"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\", \"hash-alg-id\":\"sha-384\",\"hw-vendor\":\"ACME\",\"class-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"realm-personalization-value\": \"QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==\",\"rem0\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\",\"rem1\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\",\"rem2\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\",\"rem3\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\"}}" -] diff --git a/scheme/arm-cca/test/realm/no-realm-endorsements.json b/scheme/arm-cca/test/realm/no-realm-endorsements.json deleted file mode 100644 index ad07b473..00000000 --- a/scheme/arm-cca/test/realm/no-realm-endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQID\"}}" -] diff --git a/scheme/arm-cca/test/realm/no-rem-endorsements.json b/scheme/arm-cca/test/realm/no-rem-endorsements.json deleted file mode 100644 index e1162997..00000000 --- a/scheme/arm-cca/test/realm/no-rem-endorsements.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform.config-id\": \"AQID\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"realm.reference-value\", \"attributes\":{\"realm-initial-measurement\":\"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\", \"realm-personalization-value\": \"QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==\", \"hash-alg-id\":\"sha-384\",\"hw-vendor\":\"ACME\",\"class-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}}" -] diff --git a/scheme/arm-cca/test/realm/no-rpv-endorsements.json b/scheme/arm-cca/test/realm/no-rpv-endorsements.json deleted file mode 100644 index 90ca9290..00000000 --- a/scheme/arm-cca/test/realm/no-rpv-endorsements.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform.config-id\": \"AQID\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"realm.reference-value\", \"attributes\":{\"realm-initial-measurement\":\"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\", \"hash-alg-id\":\"sha-384\",\"hw-vendor\":\"ACME\",\"class-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"rem0\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\",\"rem1\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\",\"rem2\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\",\"rem3\": \"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==\"}}" -] diff --git a/scheme/arm-cca/test/realm/rim-mismatch-endorsements.json b/scheme/arm-cca/test/realm/rim-mismatch-endorsements.json deleted file mode 100644 index b5994de2..00000000 --- a/scheme/arm-cca/test/realm/rim-mismatch-endorsements.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"ARM_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"EwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.0.0\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQID\"}}", - "{\"scheme\":\"ARM_CCA\", \"type\":\"REFERENCE_VALUE\",\"subType\": \"realm.reference-value\", \"attributes\":{\"realm-initial-measurement\":\"Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQq==\", \"hash-alg-id\":\"sha-384\",\"hw-vendor\":\"ACME\",\"class-id\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"realm-personalization-value\": \"QURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBREFEQURBRA==\",\"rem0\": \"AQID\",\"rem1\": \"AQID\",\"rem2\": \"AQID\",\"rem3\": \"AQID\"}}" -] diff --git a/scheme/arm-cca/test_vars.go b/scheme/arm-cca/test_vars.go new file mode 100644 index 00000000..af932719 --- /dev/null +++ b/scheme/arm-cca/test_vars.go @@ -0,0 +1,54 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package arm_cca + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-cca-platform-bad-no-class.cbor + corimCcaPlatformBadNoClass []byte + + //go:embed test/corim/corim-cca-platform-bad-refval-instance.cbor + corimCcaPlatformBadRefvalInstance []byte + + //go:embed test/corim/corim-cca-platform-bad-refval-mkey.cbor + corimCcaPlatformBadRefvalMkey []byte + + //go:embed test/corim/corim-cca-platform-bad-refval-no-digests.cbor + corimCcaPlatformBadRefvalNoDigests []byte + + //go:embed test/corim/corim-cca-platform-bad-refval-no-mkey.cbor + corimCcaPlatformBadRefvalNoMkey []byte + + //go:embed test/corim/corim-cca-platform-bad-refval-no-raw-value.cbor + corimCcaPlatformBadRefvalNoRawValue []byte + + //go:embed test/corim/corim-cca-platform-bad-ta-cert.cbor + corimCcaPlatformBadTaCert []byte + + //go:embed test/corim/corim-cca-platform-bad-ta-instance.cbor + corimCcaPlatformBadTaInstance []byte + + //go:embed test/corim/corim-cca-platform-bad-ta-no-instance.cbor + corimCcaPlatformBadTaNoInstance []byte + + //go:embed test/corim/corim-cca-platform-valid.cbor + corimCcaPlatformValid []byte + + //go:embed test/corim/corim-cca-realm-bad-instance.cbor + corimCcaRealmBadInstance []byte + + //go:embed test/corim/corim-cca-realm-bad-no-instance.cbor + corimCcaRealmBadNoInstance []byte + + //go:embed test/corim/corim-cca-realm-bad-no-integ-regs.cbor + corimCcaRealmBadNoIntegRegs []byte + + //go:embed test/corim/corim-cca-realm-bad-no-raw-value.cbor + corimCcaRealmBadNoRawValue []byte + + //go:embed test/corim/corim-cca-realm-valid.cbor + corimCcaRealmValid []byte +) diff --git a/scheme/arm-cca/test_vectors.go b/scheme/arm-cca/test_vectors.go deleted file mode 100644 index 71c0393c..00000000 --- a/scheme/arm-cca/test_vectors.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm_cca - -import _ "embed" - -var ( - //go:embed test/corim/unsignedCorimCcaComidCcaRefValOne.cbor - unsignedCorimCcaComidCcaRefValOne []byte - - //go:embed test/corim/unsignedCorimCcaComidCcaRefValFour.cbor - unsignedCorimCcaComidCcaRefValFour []byte - - //go:embed test/corim/unsignedCorimCcaNoProfileComidCcaRefValOne.cbor - unsignedCorimCcaNoProfileComidCcaRefValOne []byte - - //go:embed test/corim/unsignedCorimCcaNoProfileComidCcaRefValFour.cbor - unsignedCorimCcaNoProfileComidCcaRefValFour []byte - - //go:embed test/corim/unsignedCorimCcaRealmComidCcaRealm.cbor - unsignedCorimCcaRealmComidCcaRealm []byte - - //go:embed test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor - unsignedCorimCcaRealmComidCcaRealmNoClass []byte - - //go:embed test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor - unsignedCorimCcaRealmComidCcaRealmNoInstance []byte - - //go:embed test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidInstance.cbor - unsignedCorimCcaRealmComidCcaRealmInvalidInstance []byte - - //go:embed test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidClass.cbor - unsignedCorimCcaRealmComidCcaRealmInvalidClass []byte -) diff --git a/scheme/common/Makefile b/scheme/common/Makefile index 17af9614..d62f01e1 100644 --- a/scheme/common/Makefile +++ b/scheme/common/Makefile @@ -1,9 +1,7 @@ -# Copyright 2022-2024 Contributors to the Veraison project. +# Copyright 2022-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -SUBDIR := arm - include ../../mk/common.mk include ../../mk/lint.mk +include ../../mk/pkg.mk include ../../mk/test.mk -include ../../mk/subdir.mk diff --git a/scheme/common/arm/Makefile b/scheme/common/arm/Makefile deleted file mode 100644 index d0de8a0b..00000000 --- a/scheme/common/arm/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -GOPKG := github.com/veraison/services/scheme/common/arm - -SRCS := $(wildcard *.go) - -SUBDIR += platform - -include ../../../mk/common.mk -include ../../../mk/lint.mk -include ../../../mk/pkg.mk -include ../../../mk/test.mk diff --git a/scheme/common/arm/coservrepackager.go b/scheme/common/arm/coservrepackager.go deleted file mode 100644 index 877a5bd9..00000000 --- a/scheme/common/arm/coservrepackager.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package arm - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" - "github.com/veraison/swid" -) - -func EndorsementToReferenceValueTriple(e handler.Endorsement) (*comid.ValueTriple, error) { - var attrs SwAttr - - if err := json.Unmarshal(e.Attributes, &attrs); err != nil { - return nil, fmt.Errorf("unmarshalling attributes: %w", err) - } - - // mkey - - rvID, err := comid.NewPSARefValID(attrs.SignerID) - if err != nil { - return nil, fmt.Errorf("instantiating PSA reference value ID: %w", err) - } - - label := attrs.MeasurementType - if label != "" { - rvID.SetLabel(label) - } - - version := attrs.Version - if version != "" { - rvID.SetVersion(version) - } - - // mval - - m, err := comid.NewPSAMeasurement(rvID) - if err != nil { - return nil, fmt.Errorf("instantiating PSA measurement: %w", err) - } - - m.AddDigest( - swid.AlgIDFromString(attrs.MeasDesc), - attrs.MeasurementValue, - ) - - measurements := comid.NewMeasurements().Add(m) - - // env - - class := comid.NewClassImplID(comid.ImplID(attrs.ImplID)) - if class == nil { - return nil, errors.New("class identifier instantiation failed") - } - - model := attrs.Model - if model != "" { - class.SetModel(model) - } - - vendor := attrs.Vendor - if vendor != "" { - class.SetVendor(vendor) - } - - env := comid.Environment{ - Class: class, - } - - // rv triple - - return &comid.ValueTriple{ - Environment: env, - Measurements: *measurements, - }, nil -} - -func EndorsementToAttestationKeyTriple(e handler.Endorsement) (*comid.KeyTriple, error) { - var attrs TaAttr - - if err := json.Unmarshal(e.Attributes, &attrs); err != nil { - return nil, fmt.Errorf("unmarshalling attributes: %w", err) - } - - // cryptokeys - - k, err := comid.NewPKIXBase64Key(attrs.VerifKey) - if err != nil { - return nil, fmt.Errorf("crypto key instantiation failed: %w", err) - } - - ak := comid.NewCryptoKeys().Add(k) - - // env - - instance, err := comid.NewUEIDInstance(attrs.InstID) - if err != nil { - return nil, fmt.Errorf("instance identifier instantiation failed: %w", err) - } - - class := comid.NewClassImplID(comid.ImplID(attrs.ImplID)) - if class == nil { - return nil, errors.New("class identifier instantiation failed") - } - - model := attrs.Model - if model != "" { - class.SetModel(model) - } - - vendor := attrs.Vendor - if vendor != "" { - class.SetVendor(vendor) - } - - env := comid.Environment{ - Class: class, - Instance: instance, - } - - return &comid.KeyTriple{ - Environment: env, - VerifKeys: *ak, - }, nil -} diff --git a/scheme/common/arm/handlers.go b/scheme/common/arm/handlers.go deleted file mode 100644 index 0d3888ab..00000000 --- a/scheme/common/arm/handlers.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2021-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm - -import ( - "bytes" - "crypto" - "encoding/base64" - "encoding/json" - "fmt" - - "github.com/veraison/ccatoken/platform" - "github.com/veraison/psatoken" - "github.com/veraison/services/handler" - "github.com/veraison/services/log" - "github.com/veraison/services/scheme/common" -) - -type SwAttr struct { - ImplID []byte `json:"impl-id"` - Model string `json:"hw-model"` - Vendor string `json:"hw-vendor"` - MeasDesc string `json:"measurement-desc"` - MeasurementType string `json:"measurement-type"` - MeasurementValue []byte `json:"measurement-value"` - SignerID []byte `json:"signer-id"` - Version string `json:"version"` -} - -type TaAttr struct { - Model string `json:"hw-model"` - Vendor string `json:"hw-vendor"` - VerifKey string `json:"iak-pub"` - ImplID []byte `json:"impl-id"` - InstID string `json:"inst-id"` -} - -type CcaPlatformCfg struct { - ImplID []byte `json:"impl-id"` - Model string `json:"hw-model"` - Vendor string `json:"hw-vendor"` - Label string `json:"platform-config-label"` - Value []byte `json:"platform-config-id"` -} - -func SynthKeysForPlatform(scheme string, tenantID string, - refVal *handler.Endorsement, -) ([]string, error) { - - implID, err := common.GetImplID(scheme, refVal.Attributes) - if err != nil { - return nil, fmt.Errorf("unable to synthesize reference value: %w", err) - } - - lookupKey := RefValLookupKey(scheme, tenantID, implID) - log.Debugf("Scheme %s Plugin Reference Value Look Up Key= %s\n", scheme, lookupKey) - - return []string{lookupKey}, nil -} - -func GetPlatformReferenceIDs( - scheme string, - tenantID string, - claims map[string]interface{}, -) ([]string, error) { - // Using the PSA specialisation here is ok because Implementation ID is - // mandatory and shared by both PSA and CCA platform. - platformClaims, err := common.MapToPSAClaims(claims) - if err != nil { - return nil, err - } - - return []string{RefValLookupKey( - scheme, - tenantID, - MustImplIDString(platformClaims), - )}, nil -} - -func SynthKeysFromTrustAnchors(scheme string, tenantID string, - ta *handler.Endorsement, -) ([]string, error) { - implID, err := common.GetImplID(scheme, ta.Attributes) - if err != nil { - return nil, fmt.Errorf("unable to synthesize reference value: %w", err) - } - - instID, err := common.GetInstID(scheme, ta.Attributes) - if err != nil { - return nil, fmt.Errorf("unable to synthesize trust anchor abs-path: %w", err) - } - - verificationLookupKey := TaLookupKey(scheme, tenantID, implID, instID) - log.Debugf("TA verification look up key: %s", verificationLookupKey) - - coservLookupKey := TaCoservLookupKey(scheme, tenantID, instID) - log.Debugf("TA coserv look up key: %s", coservLookupKey) - - return []string{verificationLookupKey, coservLookupKey}, nil -} - -func GetTrustAnchorID(scheme string, tenantID string, claims psatoken.IClaims) (string, error) { - return TaLookupKey( - scheme, - tenantID, - MustImplIDString(claims), - MustInstIDString(claims), - ), nil -} - -func MatchSoftware(scheme string, evidence psatoken.IClaims, endorsements []handler.Endorsement) bool { - var attr SwAttr - - evidenceComponents := make(map[string]psatoken.ISwComponent) - swComps, err := evidence.GetSoftwareComponents() - if err != nil { - return false - } - for _, c := range swComps { - mval, err := c.GetMeasurementValue() - if err != nil { - return false - } - mtyp, err := c.GetMeasurementType() - if err != nil { - return false - } - key := base64.StdEncoding.EncodeToString(mval) + mtyp - evidenceComponents[key] = c - } - matched := false - for _, endorsement := range endorsements { - // If we have Endorsements we assume they match to begin with - matched = true - - if err := json.Unmarshal(endorsement.Attributes, &attr); err != nil { - log.Error("could not decode sw attributes from endorsements") - return false - } - - key := base64.StdEncoding.EncodeToString(attr.MeasurementValue) + attr.MeasurementType - evComp, ok := evidenceComponents[key] - if !ok { - matched = false - break - } - - evCompMeasurementType, _ := evComp.GetMeasurementType() - evCompSignerID, _ := evComp.GetSignerID() - evCompVersion, _ := evComp.GetVersion() - - log.Debugf("MeasurementType Evidence: %s, Endorsement: %s", evCompMeasurementType, attr.MeasurementType) - typeMatched := attr.MeasurementType == "" || attr.MeasurementType == evCompMeasurementType - sigMatched := attr.SignerID == nil || bytes.Equal(attr.SignerID, evCompSignerID) - versionMatched := attr.Version == "" || attr.Version == evCompVersion - - if !(typeMatched && sigMatched && versionMatched) { - matched = false - break - } - } - return matched -} - -func FilterRefVal(endorsements []handler.Endorsement, key string) []handler.Endorsement { - var refVal []handler.Endorsement - for _, end := range endorsements { - if end.SubType == key { - refVal = append(refVal, end) - } - } - return refVal -} - -func GetPublicKeyFromTA(scheme string, trustAnchor string) (crypto.PublicKey, error) { - var ( - endorsement handler.Endorsement - ta TaAttr - ) - - if err := json.Unmarshal([]byte(trustAnchor), &endorsement); err != nil { - return nil, fmt.Errorf("for scheme, %s, could not decode trust anchor: %w", scheme, err) - } - - if err := json.Unmarshal(endorsement.Attributes, &ta); err != nil { - return nil, fmt.Errorf("could not unmarshal trust anchor: %w", err) - } - pem := ta.VerifKey - - pk, err := common.DecodePemSubjectPubKeyInfo([]byte(pem)) - if err != nil { - return nil, fmt.Errorf("could not decode subject public key info: %w", err) - } - return pk, nil -} - -func MatchPlatformConfig(scheme string, evidence platform.IClaims, endorsements []handler.Endorsement) bool { - var attr CcaPlatformCfg - pfConfig, err := evidence.GetConfig() - if err != nil { - return false - } - - endorsementsLen := len(endorsements) - - switch endorsementsLen { - case 0: - log.Debugf("got no CCA configuration endorsement, accepting unconditionally") - return true - case 1: - break - default: - log.Errorf("got %d CCA configuration endorsements, want 1", endorsementsLen) - return false - } - - if err := json.Unmarshal(endorsements[0].Attributes, &attr); err != nil { - log.Error("could not decode cca platform config in MatchPlatformConfig") - return false - } - - return bytes.Equal(pfConfig, attr.Value) -} diff --git a/scheme/common/arm/lookup.go b/scheme/common/arm/lookup.go deleted file mode 100644 index 486c86f1..00000000 --- a/scheme/common/arm/lookup.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2021-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package arm - -import ( - "encoding/base64" - "net/url" - "strings" - - "github.com/veraison/psatoken" -) - -func RefValLookupKey(schemeName, tenantID, implID string) string { - absPath := []string{implID} - - u := url.URL{ - Scheme: schemeName, - Host: tenantID, - Path: strings.Join(absPath, "/"), - } - - return u.String() -} - -func TaLookupKey(schemeName, tenantID, implID, instID string) string { - absPath := []string{implID, instID} - - u := url.URL{ - Scheme: schemeName, - Host: tenantID, - Path: strings.Join(absPath, "/"), - } - - return u.String() -} - -func TaCoservLookupKey(schemeName, tenantID, instID string) string { - u := url.URL{ - Scheme: schemeName, - Host: tenantID, - Path: instID, - } - - return u.String() -} - -func MustImplIDString(c psatoken.IClaims) string { - v, err := c.GetImplID() - if err != nil { - panic(err) - } - - return base64.StdEncoding.EncodeToString(v) -} - -func MustInstIDString(c psatoken.IClaims) string { - v, err := c.GetInstID() - if err != nil { - panic(err) - } - - return base64.StdEncoding.EncodeToString(v) -} diff --git a/scheme/common/arm/platform/classattributes.go b/scheme/common/arm/platform/classattributes.go deleted file mode 100644 index dd7fb594..00000000 --- a/scheme/common/arm/platform/classattributes.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package platform - -import ( - "fmt" - - "github.com/veraison/corim/comid" -) - -type ClassAttributes struct { - ImplID []byte - Vendor string - Model string -} - -// extract mandatory ImplID and optional vendor & model -func (o *ClassAttributes) FromEnvironment(e comid.Environment) error { - class := e.Class - - if class == nil { - return fmt.Errorf("expecting class in environment") - } - - classID := class.ClassID - - if classID == nil { - return fmt.Errorf("expecting class-id in class") - } - - implID, err := classID.GetImplID() - if err != nil { - return fmt.Errorf("could not extract implementation-id from class-id: %w", err) - } - - o.ImplID = implID[:] - - if class.Vendor != nil { - o.Vendor = *class.Vendor - } - - if class.Model != nil { - o.Model = *class.Model - } - - return nil -} diff --git a/scheme/common/arm/platform/imeasurement.go b/scheme/common/arm/platform/imeasurement.go deleted file mode 100644 index 988cebe8..00000000 --- a/scheme/common/arm/platform/imeasurement.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package platform - -import ( - "encoding/json" - - "github.com/veraison/corim/comid" -) - -// MeasurementExtractor is an interface to extract measurements from comid -// to construct Reference Value Endorsements using Reference Value type -type MeasurementExtractor interface { - FromMeasurement(comid.Measurement) error - GetRefValType() string - // MakeRefAttrs is an interface method to populate reference attributes. - MakeRefAttrs(ClassAttributes) (json.RawMessage, error) -} diff --git a/scheme/common/arm/platform/instanceattributes.go b/scheme/common/arm/platform/instanceattributes.go deleted file mode 100644 index e0210ff5..00000000 --- a/scheme/common/arm/platform/instanceattributes.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package platform - -import ( - "errors" - - "github.com/veraison/corim/comid" - "github.com/veraison/eat" -) - -type InstanceAttributes struct { - InstID eat.UEID -} - -func (o *InstanceAttributes) FromEnvironment(e comid.Environment) error { - var err error - - if e.Instance == nil { - return errors.New("expecting instance in environment") - } - - o.InstID, err = e.Instance.GetUEID() - - return err -} diff --git a/scheme/common/arm/platform/swcompattributes.go b/scheme/common/arm/platform/swcompattributes.go deleted file mode 100644 index a4114c0d..00000000 --- a/scheme/common/arm/platform/swcompattributes.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package platform - -import ( - "encoding/json" - "fmt" - - "github.com/veraison/corim/comid" -) - -type SwCompAttributes struct { - MeasurementType string - Version string - SignerID []byte - AlgID string - MeasurementValue []byte -} - -func (o *SwCompAttributes) FromMeasurement(m comid.Measurement) error { - - if m.Key == nil { - return fmt.Errorf("measurement key is not present") - } - - // extract psa-swcomp-id from mkey - if !m.Key.IsSet() { - return fmt.Errorf("measurement key is not set") - } - - id, err := m.Key.GetPSARefValID() - if err != nil { - return fmt.Errorf("failed extracting psa-swcomp-id: %w", err) - } - - o.SignerID = id.SignerID - - if id.Label != nil { - o.MeasurementType = *id.Label - } - - if id.Version != nil { - o.Version = *id.Version - } - - // extract digest and alg-id from mval - d := m.Val.Digests - - if d == nil { - return fmt.Errorf("measurement value has no digests") - } - - if len(*d) != 1 { - return fmt.Errorf("expecting exactly one digest") - } - - o.AlgID = (*d)[0].AlgIDToString() - o.MeasurementValue = (*d)[0].HashValue - - return nil -} - -func (o SwCompAttributes) GetRefValType() string { - return "platform.sw-component" -} - -func (o *SwCompAttributes) MakeRefAttrs(c ClassAttributes) (json.RawMessage, error) { - - swAttrs := map[string]interface{}{ - "impl-id": c.ImplID, - "signer-id": o.SignerID, - "measurement-value": o.MeasurementValue, - "measurement-desc": o.AlgID, - } - - if c.Vendor != "" { - swAttrs["hw-vendor"] = c.Vendor - } - - if c.Model != "" { - swAttrs["hw-model"] = c.Model - } - - if o.MeasurementType != "" { - swAttrs["measurement-type"] = o.MeasurementType - } - - if o.Version != "" { - swAttrs["version"] = o.Version - } - msg, err := json.Marshal(swAttrs) - if err != nil { - return nil, fmt.Errorf("unable to marshal reference attributes: %w", err) - } - return msg, nil -} diff --git a/scheme/common/arm/platform/swcompattributes_test.go b/scheme/common/arm/platform/swcompattributes_test.go deleted file mode 100644 index 6ee1a83b..00000000 --- a/scheme/common/arm/platform/swcompattributes_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package platform - -import ( - "encoding/json" - "reflect" - "testing" -) - -func TestSwCompAttributes_MakeRefAttrs(t *testing.T) { - type fields struct { - MeasurementType string - Version string - SignerID []byte - AlgID string - MeasurementValue []byte - } - type args struct { - c ClassAttributes - } - tests := []struct { - name string - fields fields - args args - want json.RawMessage - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - o := &SwCompAttributes{ - MeasurementType: tt.fields.MeasurementType, - Version: tt.fields.Version, - SignerID: tt.fields.SignerID, - AlgID: tt.fields.AlgID, - MeasurementValue: tt.fields.MeasurementValue, - } - got, err := o.MakeRefAttrs(tt.args.c) - if (err != nil) != tt.wantErr { - t.Errorf("SwCompAttributes.MakeRefAttrs() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("SwCompAttributes.MakeRefAttrs() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/scheme/common/cca/Makefile b/scheme/common/cca/Makefile deleted file mode 100644 index 14e1000c..00000000 --- a/scheme/common/cca/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -GOPKG := github.com/veraison/services/scheme/common/cca - -SRCS := $(wildcard *.go) - -SUBDIR += platform -SUBDIR += realm - -include ../../../mk/common.mk -include ../../../mk/lint.mk -include ../../../mk/pkg.mk -include ../../../mk/test.mk diff --git a/scheme/common/cca/platform/cca_ssd_extractor.go b/scheme/common/cca/platform/cca_ssd_extractor.go deleted file mode 100644 index 07079dc6..00000000 --- a/scheme/common/cca/platform/cca_ssd_extractor.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package platform - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common/arm/platform" -) - -type CcaSsdExtractor struct { - Scheme string -} - -func (o CcaSsdExtractor) RefValExtractor(rvs comid.ValueTriples) ([]*handler.Endorsement, error) { - refVals := make([]*handler.Endorsement, 0, len(rvs.Values)) - - for _, rv := range rvs.Values { - var classAttrs platform.ClassAttributes - var refVal *handler.Endorsement - var err error - - if err := classAttrs.FromEnvironment(rv.Environment); err != nil { - return nil, fmt.Errorf("could not extract PSA class attributes: %w", err) - } - for i, m := range rv.Measurements.Values { - if m.Key == nil { - return nil, fmt.Errorf("measurement key is not set at index %d ", i) - } - - if !m.Key.IsSet() { - return nil, fmt.Errorf("measurement key is not set") - } - - // Check which MKey is present and then decide which extractor to invoke - switch m.Key.Type() { - case comid.PSARefValIDType: - var swCompAttrs platform.SwCompAttributes - - refVal, err = o.extractMeasurement( - &swCompAttrs, - m, - classAttrs, - ) - if err != nil { - return nil, fmt.Errorf( - "unable to extract measurement at index %d, %w", - i, - err, - ) - } - case comid.CCAPlatformConfigIDType: - var ccaPlatformConfigID CCAPlatformConfigID - refVal, err = o.extractMeasurement( - &ccaPlatformConfigID, - m, - classAttrs, - ) - if err != nil { - return nil, fmt.Errorf("unable to extract measurement: %w", err) - } - default: - return nil, fmt.Errorf( - "unknown measurement key: %T", - reflect.TypeOf(m.Key), - ) - } - refVals = append(refVals, refVal) - } - } - - if len(refVals) == 0 { - return nil, fmt.Errorf("no software components found") - } - - return refVals, nil -} - -func (o CcaSsdExtractor) extractMeasurement( - obj platform.MeasurementExtractor, - m comid.Measurement, - class platform.ClassAttributes, -) (*handler.Endorsement, error) { - if err := obj.FromMeasurement(m); err != nil { - return nil, err - } - - refAttrs, err := obj.MakeRefAttrs(class) - if err != nil { - return &handler.Endorsement{}, fmt.Errorf("failed to create software component attributes: %w", err) - } - refVal := handler.Endorsement{ - Scheme: o.Scheme, - Type: handler.EndorsementType_REFERENCE_VALUE, - SubType: obj.GetRefValType(), - Attributes: refAttrs, - } - return &refVal, nil -} - -func (o CcaSsdExtractor) TaExtractor(avk comid.KeyTriple) (*handler.Endorsement, error) { - // extract implementation ID - var classAttrs platform.ClassAttributes - if err := classAttrs.FromEnvironment(avk.Environment); err != nil { - return nil, fmt.Errorf("could not extract PSA class attributes: %w", err) - } - - // extract instance ID - var instanceAttrs platform.InstanceAttributes - if err := instanceAttrs.FromEnvironment(avk.Environment); err != nil { - return nil, fmt.Errorf("could not extract PSA instance-id: %w", err) - } - - // extract IAK pub - if len(avk.VerifKeys) != 1 { - return nil, errors.New("expecting exactly one IAK public key") - } - - iakPub := avk.VerifKeys[0] - if _, ok := iakPub.Value.(*comid.TaggedPKIXBase64Key); !ok { - return nil, fmt.Errorf("IAK does not appear to be a PEM key (%T)", iakPub.Value) - } - - taAttrs, err := makeTaAttrs(instanceAttrs, classAttrs, iakPub) - if err != nil { - return nil, fmt.Errorf("failed to create trust anchor attributes: %w", err) - } - - // note we do not need a subType for TA - ta := &handler.Endorsement{ - Scheme: o.Scheme, - Type: handler.EndorsementType_VERIFICATION_KEY, - Attributes: taAttrs, - } - - return ta, nil -} - -func makeTaAttrs( - i platform.InstanceAttributes, - c platform.ClassAttributes, - key *comid.CryptoKey, -) (json.RawMessage, error) { - taID := map[string]interface{}{ - "impl-id": c.ImplID, - "inst-id": []byte(i.InstID), - "iak-pub": key.String(), - } - - if c.Vendor != "" { - taID["hw-vendor"] = c.Vendor - } - - if c.Model != "" { - taID["hw-model"] = c.Model - } - - msg, err := json.Marshal(taID) - if err != nil { - return nil, fmt.Errorf("unable to marshal TA attributes: %w", err) - } - return msg, nil -} diff --git a/scheme/common/cca/platform/ccaplatformconfigid.go b/scheme/common/cca/platform/ccaplatformconfigid.go deleted file mode 100644 index 9faf4f27..00000000 --- a/scheme/common/cca/platform/ccaplatformconfigid.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package platform - -import ( - "encoding/json" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/scheme/common/arm/platform" -) - -type CCAPlatformConfigID struct { - Label string - Value []byte -} - -func (o *CCAPlatformConfigID) FromMeasurement(m comid.Measurement) error { - id, err := m.Key.GetCCAPlatformConfigID() - if err != nil { - return fmt.Errorf("failed extracting mkey for cca-platform-config-id: %w", err) - } - o.Label = string(id) - - if m.Val.RawValue == nil { - return fmt.Errorf("no CCA platform config id set in the measurements") - } - r := *m.Val.RawValue - - o.Value, err = r.GetBytes() - if err != nil { - return fmt.Errorf("failed to get CCA platform config id: %w", err) - } - return nil -} - -func (o CCAPlatformConfigID) GetRefValType() string { - return "platform.config" -} - -// For CCAPlatformConfigID object, scheme argument is not strictly required, but is required for other -// usage of the same interface -func (o CCAPlatformConfigID) MakeRefAttrs(c platform.ClassAttributes) (json.RawMessage, error) { - refAttrs := map[string]interface{}{ - "impl-id": c.ImplID, - "platform-config-label": o.Label, - "platform-config-id": o.Value, - } - - if c.Vendor != "" { - refAttrs["hw-vendor"] = c.Vendor - } - - if c.Model != "" { - refAttrs["hw-model"] = c.Model - } - - msg, err := json.Marshal(refAttrs) - if err != nil { - return nil, fmt.Errorf("unable to marshal CCA platform configuration attributes: %w", err) - } - return msg, nil -} diff --git a/scheme/common/cca/realm/realm_attributes.go b/scheme/common/cca/realm/realm_attributes.go deleted file mode 100644 index b810d3d5..00000000 --- a/scheme/common/cca/realm/realm_attributes.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package realm - -import ( - "errors" - "fmt" - "strings" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/log" -) - -type RealmAttributes struct { - RIM *[]byte - REM [4]*[]byte - HashAlgID string - RPV *[]byte -} - -func (o *RealmAttributes) FromMeasurement(m comid.Measurement) error { - if err := o.extractRealmPersonalizationValue(m.Val.RawValue); err != nil { - return fmt.Errorf("extracting rpv: %w", err) - } - if err := o.extractRegisterIndexes(m.Val.IntegrityRegisters); err != nil { - return fmt.Errorf("extracting measurement: %w", err) - } - - if err := o.Valid(); err != nil { - return fmt.Errorf("extracting realm attributes: %w", err) - } - return nil -} - -func (o *RealmAttributes) GetRefValType() string { - return "realm.reference-value" -} - -func (o *RealmAttributes) extractRealmDigest(digests comid.Digests) (algID string, hash []byte, err error) { - if err := digests.Valid(); err != nil { - return "", nil, fmt.Errorf("invalid digest: %v", err) - } - if len(digests) != 1 { - return "", nil, fmt.Errorf("expecting 1 digest, got %d", len(digests)) - } - - return digests[0].AlgIDToString(), digests[0].HashValue, nil -} - -func (o *RealmAttributes) extractRegisterIndexes(r *comid.IntegrityRegisters) error { - for k, val := range r.IndexMap { - a, d, err := o.extractRealmDigest(val) - if err != nil { - return fmt.Errorf("unable to extract realm digest: %v", err) - } - switch t := k.(type) { - case string: - key := strings.ToLower(t) - if !o.isCompatibleAlgID(a) { - return fmt.Errorf("incompatible AlgID %s for key %s", a, key) - } - switch key { - case "rim": - o.HashAlgID = a - o.RIM = &d - case "rem0": - o.REM[0] = &d - case "rem1": - o.REM[1] = &d - case "rem2": - o.REM[2] = &d - case "rem3": - o.REM[3] = &d - default: - return fmt.Errorf("unexpected register index: %s", key) - } - default: - return fmt.Errorf("unexpected type for index: %T", t) - } - } - return nil -} - -func (o RealmAttributes) isCompatibleAlgID(hashAlgID string) bool { - return o.HashAlgID == "" || hashAlgID == o.HashAlgID -} - -func (o *RealmAttributes) extractRealmPersonalizationValue(r *comid.RawValue) error { - var err error - if r == nil { - log.Debug("realm personalization value not present") - return nil - } - rpv, err := r.GetBytes() - if err != nil { - return err - } else if len(rpv) != 64 { - return fmt.Errorf("invalid length %d for realm personalization value", len(rpv)) - } - o.RPV = &rpv - return nil -} - -func (o *RealmAttributes) Valid() error { - if o.RIM == nil { - return errors.New("no realm initial measurements") - } - return nil -} diff --git a/scheme/common/cca/realm/realm_classattributes.go b/scheme/common/cca/realm/realm_classattributes.go deleted file mode 100644 index a889c3fc..00000000 --- a/scheme/common/cca/realm/realm_classattributes.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package realm - -import ( - "errors" - "fmt" - - "github.com/veraison/corim/comid" -) - -type RealmClassAttributes struct { - UUID *string - Vendor *string -} - -// extract class variables from environment -func (o *RealmClassAttributes) FromEnvironment(e comid.Environment) error { - class := e.Class - - if class == nil { - return nil - } - - classID := class.ClassID - if classID != nil { - UUID, err := classID.GetUUID() - if err != nil { - return fmt.Errorf("could not extract uuid from class-id: %w", err) - } - - if err := UUID.Valid(); err != nil { - return fmt.Errorf("no valid uuid: %w", err) - } - uuid := UUID.String() - o.UUID = &uuid - } else { - if class.Vendor != nil { - o.Vendor = class.Vendor - } else { - return errors.New("class is neither a classID or a vendor name") - } - } - - return nil -} diff --git a/scheme/common/cca/realm/realm_extractor.go b/scheme/common/cca/realm/realm_extractor.go deleted file mode 100644 index 76719f78..00000000 --- a/scheme/common/cca/realm/realm_extractor.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package realm - -import ( - "encoding/json" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" -) - -type RealmExtractor struct { - Scheme string -} - -func (o RealmExtractor) RefValExtractor(rvs comid.ValueTriples) ([]*handler.Endorsement, error) { - // Measurements are encoded in a measurement-map of a CoMID - // reference-triple-record. For a Realm Instance, all the measurements - // which comprise both the "RIM" & "REM" measurements are carried in an - // integrity register - refVals := make([]*handler.Endorsement, 0, len(rvs.Values)) - - for _, rv := range rvs.Values { - var classAttrs RealmClassAttributes - var instAttrs RealmInstanceAttributes - var refVal *handler.Endorsement - var rAttr RealmAttributes - - if err := classAttrs.FromEnvironment(rv.Environment); err != nil { - return nil, fmt.Errorf( - "could not extract Realm class attributes: %w", - err, - ) - } - - if err := instAttrs.FromEnvironment(rv.Environment); err != nil { - return nil, fmt.Errorf( - "could not extract Realm instance attributes: %w", - err, - ) - } - for _, m := range rv.Measurements.Values { - if err := rAttr.FromMeasurement(m); err != nil { - return nil, fmt.Errorf( - "unable to extract realm reference attributes from measurement: %w", - err, - ) - } - refAttrs, err := makeRefValAttrs(&classAttrs, &rAttr) - if err != nil { - return nil, fmt.Errorf("unable to make reference attributes: %w", err) - } - refVal = &handler.Endorsement{ - Scheme: o.Scheme, - Type: handler.EndorsementType_REFERENCE_VALUE, - SubType: rAttr.GetRefValType(), - Attributes: refAttrs, - } - refVals = append(refVals, refVal) - } - } - - if len(refVals) == 0 { - return nil, fmt.Errorf("no measurements found") - } - - return refVals, nil -} - -func makeRefValAttrs( - cAttr *RealmClassAttributes, - rAttr *RealmAttributes, -) (json.RawMessage, error) { - - var attrs = map[string]interface{}{ - "realm-initial-measurement": *rAttr.RIM, - "hash-alg-id": rAttr.HashAlgID, - } - if rAttr.RPV != nil { - attrs["realm-personalization-value"] = *rAttr.RPV - } - - if cAttr.Vendor != nil { - attrs["vendor"] = *cAttr.Vendor - } - if cAttr.UUID != nil { - attrs["class-id"] = *cAttr.UUID - } - if rAttr.REM[0] != nil { - attrs["rem0"] = *rAttr.REM[0] - } - if rAttr.REM[1] != nil { - attrs["rem1"] = *rAttr.REM[1] - } - if rAttr.REM[2] != nil { - attrs["rem2"] = *rAttr.REM[2] - } - if rAttr.REM[3] != nil { - attrs["rem3"] = *rAttr.REM[3] - } - - data, err := json.Marshal(attrs) - if err != nil { - return nil, fmt.Errorf("unable to marshal reference value attributes: %w", err) - } - return data, nil -} diff --git a/scheme/common/cca/realm/realm_handlers.go b/scheme/common/cca/realm/realm_handlers.go deleted file mode 100644 index 29b72947..00000000 --- a/scheme/common/cca/realm/realm_handlers.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package realm - -import ( - "encoding/base64" - "fmt" - - "github.com/veraison/services/handler" - "github.com/veraison/services/log" -) - -func SynthKeysForCcaRealm(scheme string, tenantID string, - refVal *handler.Endorsement, -) ([]string, error) { - rim, err := GetRIM(refVal.Attributes) - if err != nil { - return nil, fmt.Errorf("unable to get rim %w", err) - } - lookupKey := RealmRefValLookupKey(scheme, tenantID, rim) - log.Debugf("Scheme %s Plugin Reference Value Look Up Key= %s\n", scheme, lookupKey) - return []string{lookupKey}, nil -} - -func GetRealmReferenceIDs( - scheme string, - tenantID string, - realmClaimsMap map[string]interface{}, -) ([]string, error) { - realmClaims, err := MapToRealmClaims(realmClaimsMap) - if err != nil { - return nil, err - } - m, err := realmClaims.GetInitialMeasurement() - if err != nil { - return nil, err - } - rim := base64.StdEncoding.EncodeToString(m) - return []string{RealmRefValLookupKey(scheme, tenantID, rim)}, nil -} diff --git a/scheme/common/cca/realm/realm_instanceattributes.go b/scheme/common/cca/realm/realm_instanceattributes.go deleted file mode 100644 index 7165167b..00000000 --- a/scheme/common/cca/realm/realm_instanceattributes.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package realm - -import ( - "errors" - - "github.com/veraison/corim/comid" -) - -type RealmInstanceAttributes struct { - InstID string -} - -func (o *RealmInstanceAttributes) FromEnvironment(e comid.Environment) error { - var err error - - if e.Instance == nil { - return errors.New("expecting instance in environment") - } - - if e.Instance.Type() != "bytes" { - return errors.New("expecting instance as bytes for CCA Realm") - } - b := e.Instance.Bytes() - - o.InstID = string(b) - return err -} diff --git a/scheme/common/cca/realm/realm_utils.go b/scheme/common/cca/realm/realm_utils.go deleted file mode 100644 index d81c2ebd..00000000 --- a/scheme/common/cca/realm/realm_utils.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package realm - -import ( - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "net/url" - "strings" - - "github.com/veraison/ccatoken/realm" - "github.com/veraison/services/log" -) - -func GetRIM(attr json.RawMessage) (string, error) { - var at map[string]interface{} - err := json.Unmarshal(attr, &at) - if err != nil { - return "", fmt.Errorf("unable to get RIM: %w", err) - } - rim, ok := at["realm-initial-measurement"].(string) - if !ok { - return "", errors.New("unable to get realm initial measurements") - } - return rim, nil -} - -func GetRPV(attr json.RawMessage) ([]byte, error) { - var at map[string]interface{} - err := json.Unmarshal(attr, &at) - if err != nil { - return nil, err - } - iv := at["realm-personalization-value"] - if iv == nil { - return nil, nil - } - v, ok := iv.(string) - if !ok { - return nil, fmt.Errorf("unable to get realm personalization value from %v of type %T", iv, iv) - } - rpv, err := base64.StdEncoding.DecodeString(v) - if err != nil { - return nil, err - } - return rpv, nil -} - -func GetREMs(attr json.RawMessage) ([][]byte, error) { - var at map[string]interface{} - var rems [][]byte - keys := []string{"rem0", "rem1", "rem2", "rem3"} - err := json.Unmarshal(attr, &at) - if err != nil { - return nil, err - } - for _, key := range keys { - rem, ok := at[key].(string) - if ok { - brem, err := base64.StdEncoding.DecodeString(rem) - if err != nil { - return nil, err - } - rems = append(rems, brem) - } else { - log.Debugf("No Rem with key = %s", key) - break - } - } - return rems, nil -} - -func MapToRealmClaims(in map[string]interface{}) (realm.IClaims, error) { - data, err := json.Marshal(in) - if err != nil { - return nil, err - } - - realmClaims, err := realm.DecodeClaimsFromJSON(data) - if err != nil { - return nil, err - } - - return realmClaims, nil -} - -func RealmRefValLookupKey(schemeName, tenantID, rim string) string { - absPath := []string{rim} - - u := url.URL{ - Scheme: schemeName, - Host: tenantID, - Path: strings.Join(absPath, "/"), - } - - return u.String() -} diff --git a/scheme/common/corim.go b/scheme/common/corim.go new file mode 100644 index 00000000..dafd30cb --- /dev/null +++ b/scheme/common/corim.go @@ -0,0 +1,160 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package common + +import ( + "crypto" + "errors" + "fmt" + "iter" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" +) + +// / CorimTestCase defines a test case for checking whether the specified CoRIM +// loads as expected. +type CorimTestCase struct { + Title string + Input []byte + Err string +} + +// RunCorimTests run the provided CorimTestCase's. +func RunCorimTests(t *testing.T, tcs []CorimTestCase) { + for _, tc := range tcs { + t.Run(tc.Title, func(t *testing.T) { + _, err := corim.UnmarshalAndValidateUnsignedCorimFromCBOR(tc.Input) + if tc.Err == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.Err) + } + }) + } +} + +// ExtractOneVerifKey returns the single CryptoKey contained within provided trust +// anchors. If there is more than one trust anchor supplied, or if it contains +// more than one VerifKey, an error is returned instead. +func ExtractOneVerifKey(trustAnchors []*comid.KeyTriple) (*comid.CryptoKey, error) { + numTAs := len(trustAnchors) + if numTAs != 1 { + return nil, fmt.Errorf("expected exactly 1 trust anchor; found %d", numTAs) + } + + numKeys := len(trustAnchors[0].VerifKeys) + if numKeys != 1 { + return nil, fmt.Errorf("expected exactly 1 verif. key in triple; found %d", numKeys) + } + + return trustAnchors[0].VerifKeys[0], nil +} + +// ExtractPublicKeyFromTrustAnchors extracts the PublicKey in the common case +// where there is exactly one KeyTriple in the trust anchors, and exactly one +// VerifKey inside the triple. +func ExtractPublicKeyFromTrustAnchors(trustAnchors []*comid.KeyTriple) (crypto.PublicKey, error) { + vk, err := ExtractOneVerifKey(trustAnchors) + if err != nil { + return nil, err + } + + return vk.PublicKey() +} + +type IEnvironmentValidator func(*comid.Environment) error +type ICryptoKeysValid func(keys []*comid.CryptoKey) error +type IMeasurementsValidator func(measurements []comid.Measurement) error + +// TriplesValidator implements generic logic for validating comid.Triples +// based on provided callbacks. This can be registered as a comid.ExtTriples +// extensions for a profile, so that it is automatically invoked when a CoRIM +// with that profile is loaded. +type TriplesValidator struct { + EnviromentValidator IEnvironmentValidator `cbor:"-" json:"-"` + RefValEnviromentValidator IEnvironmentValidator `cbor:"-" json:"-"` + TAEnviromentValidator IEnvironmentValidator `cbor:"-" json:"-"` + + CryptoKeysValidator ICryptoKeysValid `cbor:"-" json:"-"` + MeasurementsValidator IMeasurementsValidator `cbor:"-" json:"-"` + + DisallowTAs bool `cbor:"-" json:"-"` + DisallowRefVals bool `cbor:"-" json:"-"` +} + +func (o *TriplesValidator) ValidTriples(triples *comid.Triples) error { + taSeen := false + for i, kt := range Enumerate(triples.IterAttestVerifKeys()) { + taSeen = true + + if o.DisallowTAs { + return errors.New("found trust anchors (disallowed by scheme)") + } + + if o.TAEnviromentValidator != nil { + if err := o.TAEnviromentValidator(&kt.Environment); err != nil { + return fmt.Errorf("trust anchor %d environment: %w", i, err) + } + } else if o.EnviromentValidator != nil { + if err := o.EnviromentValidator(&kt.Environment); err != nil { + return fmt.Errorf("trust anchor %d environment: %w", i, err) + } + } + + if o.CryptoKeysValidator != nil { + if err := o.CryptoKeysValidator(kt.VerifKeys); err != nil { + return fmt.Errorf("trust anchor %d verif. keys: %w", i, err) + } + } + } + + refValSeen := false + for i, vt := range Enumerate(triples.IterRefVals()) { + refValSeen = true + + if o.DisallowRefVals { + return errors.New("found reference values (disallowed by scheme)") + } + + if o.RefValEnviromentValidator != nil { + if err := o.RefValEnviromentValidator(&vt.Environment); err != nil { + return fmt.Errorf("reference value %d environment: %w", i, err) + } + } else if o.EnviromentValidator != nil { + if err := o.EnviromentValidator(&vt.Environment); err != nil { + return fmt.Errorf("reference value %d environment: %w", i, err) + } + } + + if o.MeasurementsValidator != nil { + if err := o.MeasurementsValidator(vt.Measurements.Values); err != nil { + return fmt.Errorf("trust anchor %d measurements: %w", i, err) + } + } + } + + if !taSeen && !refValSeen { + return errors.New("no reference values or trust anchors in CoMID triples") + } + + return nil +} + +// Enumerate transforms an iter.Seq[T] into iter.Seq2[int, T], with the +// first value in Seq being the ordinal (starting at 0) of the associated +// T within the sequence. +// (side note: this really ought to be part of iter package...) +func Enumerate[T any](seq iter.Seq[T]) iter.Seq2[int, T] { + return func(yield func(int, T) bool) { + i := 0 + for v := range seq { + if !yield(i, v) { + return + } + i++ + } + } +} diff --git a/scheme/common/iextractor.go b/scheme/common/iextractor.go deleted file mode 100644 index 777e3a99..00000000 --- a/scheme/common/iextractor.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package common - -import ( - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" -) - -// IExtractor is the interface that CoRIM plugins need to implement to hook into -// the UnsignedCorimDecoder logics. -// Each extractor consumes a specific CoMID triple and produces a corresponding -// Veraison Endorsement format (or an error). -// -// Note: At the moment the interface is limited by the known use cases. We -// anticipate that in the future there will to be an extractor for each of the -// defined CoMID triples, plus maybe a way to handle cross-triples checks as -// well as extraction from the "global" CoRIM context. -// See also https://github.com/veraison/services/issues/70 -type IExtractor interface { - RefValExtractor(comid.ValueTriples) ([]*handler.Endorsement, error) - TaExtractor(comid.KeyTriple) (*handler.Endorsement, error) - SetProfile(string) -} diff --git a/scheme/common/scripts/gen-corim b/scheme/common/scripts/gen-corim deleted file mode 100755 index 9689922e..00000000 --- a/scheme/common/scripts/gen-corim +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 -# This script constructs a CBOR CoRIM for use in test vectors, using supplied -# comid and corim json template and saves them in a file -# $1 directory into which the CoRIM should be generated; it must contain "src/" -# subdirectory with the templates specifie dby th use case. -# $2 file name for comid json template, example one of COMID_TEMPLATES -# $3 file name for corim json template, example CORIM_TEMPLATE -# $4 a qualifier for each cbor test vector name - -TEST_DIR=$1 -COMID=$2 -CORIM=$3 -QUALIFIER=$4 - -echo "generating test vector using $COMID $CORIM" -cocli comid create -t "$TEST_DIR/src/$COMID.json" -o "$TEST_DIR" -cocli corim create -m "$TEST_DIR/$COMID.cbor" -t "$TEST_DIR/src/$CORIM.json" \ - -o "$TEST_DIR/$QUALIFIER${CORIM^}${COMID^}.cbor" -rm "$TEST_DIR/$COMID.cbor" diff --git a/scheme/common/signedcorim_decoder.go b/scheme/common/signedcorim_decoder.go deleted file mode 100644 index ead8ae7f..00000000 --- a/scheme/common/signedcorim_decoder.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package common - -import ( - "crypto/sha256" - "crypto/x509" - "encoding/hex" - "fmt" - - "github.com/veraison/corim/corim" - "github.com/veraison/services/handler" -) - -// calculateCertThumbprint computes the SHA-256 thumbprint of an X.509 certificate -func calculateCertThumbprint(cert *x509.Certificate) (string, error) { - if cert == nil { - return "", fmt.Errorf("certificate is nil") - } - - thumbprint := sha256.Sum256(cert.Raw) - hexStr := hex.EncodeToString(thumbprint[:]) - - return hexStr, nil -} - -// SignedCorimDecoder processes a signed CoRIM, verifies its signature, and then -// passes the unsigned CoRIM to the UnsignedCorimDecoder for further processing. -func SignedCorimDecoder( - data []byte, - xtr IExtractor, - caCertPoolPEM []byte, -) (*handler.EndorsementHandlerResponse, error) { - if len(data) == 0 { - return nil, fmt.Errorf("empty corim data") - } - - // Parse the signed CoRIM which extracts certificate chain automatically through extractX5Chain - sc := corim.NewSignedCorim() - if err := sc.FromCOSE(data); err != nil { - return nil, fmt.Errorf("failed to parse signed CoRIM: %w", err) - } - - if sc.SigningCert == nil { - return nil, fmt.Errorf("no signing certificate found in the CoRIM") - } - - rootCertPool, err := x509.SystemCertPool() - if err != nil { - return nil, fmt.Errorf("could not load system certificates: %w", err) - } - - // CA certs must be provided for verification - if len(caCertPoolPEM) == 0 { - return nil, fmt.Errorf("no CA certificates available for verification") - } - - // Add the CA certificates from the provided PEM data - if !rootCertPool.AppendCertsFromPEM(caCertPoolPEM) { - return nil, fmt.Errorf("failed to parse and append CA certificates from the cert pool") - } - - // Create a separate pool for intermediate certificates - intermediateCertPool := x509.NewCertPool() - for _, cert := range sc.IntermediateCerts { - intermediateCertPool.AddCert(cert) - } - - // Verify the certificate chain with properly separated root and intermediate pools - verifyOpts := x509.VerifyOptions{ - Roots: rootCertPool, - Intermediates: intermediateCertPool, - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, - } - - _, err = sc.SigningCert.Verify(verifyOpts) - if err != nil { - return nil, fmt.Errorf("certificate chain verification failed: %w", err) - } - - // Verify the signature using the signing certificate's public key - if err := sc.Verify(sc.SigningCert.PublicKey); err != nil { - return nil, fmt.Errorf("signature verification failed: %w", err) - } - - unsignedCorimCBOR, err := sc.UnsignedCorim.ToCBOR() - if err != nil { - return nil, fmt.Errorf("failed to CBOR serialize unsigned CoRIM: %w", err) - } - - // Calculate the signing certificate thumbprint - thumbprint, err := calculateCertThumbprint(sc.SigningCert) - if err != nil { - return nil, fmt.Errorf("failed to calculate certificate thumbprint: %w", err) - } - - return UnsignedCorimDecoder(unsignedCorimCBOR, xtr, thumbprint) -} diff --git a/scheme/common/unsignedcorim_decoder.go b/scheme/common/unsignedcorim_decoder.go deleted file mode 100644 index e17083d2..00000000 --- a/scheme/common/unsignedcorim_decoder.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package common - -import ( - "errors" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/corim/corim" - "github.com/veraison/services/handler" -) - -func UnsignedCorimDecoder( - data []byte, - xtr IExtractor, - signerThumbprint ...string, -) (*handler.EndorsementHandlerResponse, error) { - if len(data) == 0 { - return nil, errors.New("empty data") - } - - var uc corim.UnsignedCorim - if err := uc.FromCBOR(data); err != nil { - return nil, fmt.Errorf("CBOR decoding failed: %w", err) - } - - if err := uc.Valid(); err != nil { - return nil, fmt.Errorf("invalid unsigned corim: %w", err) - } - - if uc.Profile != nil { - profile, err := uc.Profile.Get() - if err != nil { - return nil, fmt.Errorf("failed to get the profile information: %w", err) - } - xtr.SetProfile(profile) - } else { - return nil, fmt.Errorf("no profile information set in CoRIM") - } - - rsp := handler.EndorsementHandlerResponse{} - - for i, tag := range uc.Tags { - if tag.Number != corim.ComidTag { - return nil, fmt.Errorf("unknown CBOR tag %x detected at index %d", tag.Number, i) - } - - var c comid.Comid - - err := c.FromCBOR(tag.Content) - if err != nil { - return nil, fmt.Errorf("decoding failed for CoMID at index %d: %w", i, err) - } - - if err := c.Valid(); err != nil { - return nil, fmt.Errorf("decoding failed for CoMID at index %d: %w", i, err) - } - - if c.Triples.ReferenceValues != nil { - refVals, err := xtr.RefValExtractor(*c.Triples.ReferenceValues) - if err != nil { - return nil, fmt.Errorf( - "bad software component in CoMID at index %d: %w", - i, - err, - ) - } - - for _, refVal := range refVals { - rsp.ReferenceValues = append(rsp.ReferenceValues, *refVal) - } - } - - if c.Triples.AttestVerifKeys != nil { - for _, avk := range *c.Triples.AttestVerifKeys { - k, err := xtr.TaExtractor(avk) - if err != nil { - return nil, fmt.Errorf( - "bad key in CoMID at index %d: %w", - i, - err, - ) - } - - rsp.TrustAnchors = append(rsp.TrustAnchors, *k) - } - } - - // silently ignore any other triples - } - - return &rsp, nil -} diff --git a/scheme/common/util.go b/scheme/common/util.go new file mode 100644 index 00000000..3705face --- /dev/null +++ b/scheme/common/util.go @@ -0,0 +1,50 @@ +// Copyright 2021-2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package common + +import ( + "crypto" + "crypto/x509" + "encoding/json" + "encoding/pem" + "errors" + "fmt" +) + +// DecodePublicKeyPEM decodes a PEM encoded SubjectPublicKeyInfo. +func DecodePublicKeyPEM(key []byte) (crypto.PublicKey, error) { + block, rest := pem.Decode(key) + if block == nil { + return nil, errors.New("could not extract trust anchor PEM block") + } + + if len(rest) != 0 { + return nil, errors.New("trailing data found after PEM block") + } + + if block.Type != "PUBLIC KEY" { + return nil, fmt.Errorf("unsupported key type: %q", block.Type) + } + + pk, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("unable to parse public key: %w", err) + } + return pk, nil +} + +// ToMapViaJSON converts any value into a map[string]any by transcoding it via +// JSON. +func ToMapViaJSON(val any) (map[string]any, error) { + encoded, err := json.Marshal(val) + if err != nil { + return nil, err + } + + var ret map[string]any + if err := json.Unmarshal(encoded, &ret); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/scheme/common/utils.go b/scheme/common/utils.go deleted file mode 100644 index f3d78ebd..00000000 --- a/scheme/common/utils.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package common - -import ( - "crypto" - "crypto/x509" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - - "github.com/veraison/ccatoken/platform" - "github.com/veraison/ccatoken/realm" - "github.com/veraison/psatoken" -) - -type CcaPlatformWrapper struct { - C platform.IClaims -} - -func (o CcaPlatformWrapper) MarshalJSON() ([]byte, error) { - return platform.ValidateAndEncodeClaimsToJSON(o.C) -} - -type CcaRealmWrapper struct { - C realm.IClaims -} - -func (o CcaRealmWrapper) MarshalJSON() ([]byte, error) { - return realm.ValidateAndEncodeClaimsToJSON(o.C) -} - -type PsaPlatformWrapper struct { - C psatoken.IClaims -} - -func (o PsaPlatformWrapper) MarshalJSON() ([]byte, error) { - return psatoken.ValidateAndEncodeClaimsToJSON(o.C) -} - -type ClaimMapper interface { - MarshalJSON() ([]byte, error) -} - -func ClaimsToMap(mapper ClaimMapper) (map[string]interface{}, error) { - data, err := mapper.MarshalJSON() - if err != nil { - return nil, err - } - - var out map[string]interface{} - err = json.Unmarshal(data, &out) - - return out, err -} - -func MapToPSAClaims(in map[string]interface{}) (psatoken.IClaims, error) { - data, err := json.Marshal(in) - if err != nil { - return nil, err - } - - return psatoken.DecodeAndValidateClaimsFromJSON(data) -} - -func MapToCCAPlatformClaims(in map[string]interface{}) (platform.IClaims, error) { - data, err := json.Marshal(in) - if err != nil { - return nil, err - } - - return platform.DecodeAndValidateClaimsFromJSON(data) -} - -func GetImplID(scheme string, attr json.RawMessage) (string, error) { - var at map[string]interface{} - - err := json.Unmarshal(attr, &at) - if err != nil { - return "", fmt.Errorf("unable to get Implementation ID for scheme: %s %w", scheme, err) - } - key := "impl-id" - implID, ok := at[key].(string) - if !ok { - return "", fmt.Errorf("unable to get Implementation ID for scheme: %s", scheme) - } - return implID, nil -} - -func GetInstID(scheme string, attr json.RawMessage) (string, error) { - var at map[string]interface{} - err := json.Unmarshal(attr, &at) - if err != nil { - return "", fmt.Errorf("unable to get Instance ID: %w", err) - } - key := "inst-id" - instID, ok := at[key].(string) - if !ok { - return "", errors.New("unable to get Instance ID") - } - return instID, nil -} - -// DecodePemSubjectPubKeyInfo decodes a PEM encoded SubjectPublicKeyInfo -func DecodePemSubjectPubKeyInfo(key []byte) (crypto.PublicKey, error) { - block, rest := pem.Decode(key) - if block == nil { - return nil, errors.New("could not extract trust anchor PEM block") - } - - if len(rest) != 0 { - return nil, errors.New("trailing data found after PEM block") - } - - if block.Type != "PUBLIC KEY" { - return nil, fmt.Errorf("unsupported key type: %q", block.Type) - } - - pk, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return nil, fmt.Errorf("unable to parse public key: %w", err) - } - return pk, nil -} diff --git a/scheme/example/Makefile b/scheme/example/Makefile new file mode 100644 index 00000000..1d419984 --- /dev/null +++ b/scheme/example/Makefile @@ -0,0 +1,14 @@ +# Copyright Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +.DEFAULT_GOAL := test + +GOPKG := github.com/veraison/services/scheme/ +SRCS := $(wildcard *.go) + +SUBDIR += plugin + +include ../../mk/common.mk +include ../../mk/lint.mk +include ../../mk/pkg.mk +include ../../mk/subdir.mk +include ../../mk/test.mk diff --git a/scheme/example/README.md b/scheme/example/README.md new file mode 100644 index 00000000..15f0642a --- /dev/null +++ b/scheme/example/README.md @@ -0,0 +1,28 @@ +This directory contains the boilerplate structure for a new attestation scheme +implementation. It is intended as a starting point. + +To create a new attestation scheme: + +1. Copy the contents of this directory into a new subdirectory under scheme, + e.g. `cp -r scheme/example scheme/my-scheme`. +2. Update the `` placeholders with relevant information, keeping the + following conventions in mind: + - `SchemeName` ought to be in all caps, with underscores separating words, + e.g. `"MY_SCHEME"` + - `GOPKG` should contain the scheme name in all lower case with dashes + instead of underscores, e.g. + + GOPKG := github.com/veraison/services/scheme/my-scheme + + (note: Go automatically translates dashes to underscores in package names + when parsing source, so your source files should specify package as + `package my_scheme`). + - The name of the plugin executable should be the same name as `GOPKG` but + prefixed with `scheme-` (this is to distinguish from CoSERV backend + plugins) and use `.plugin` extension, e.g. + + PLUGIN := ../../bin/scheme-my-plugin.plugin + +3. Update `scheme/Makefile` with a `SUBDIR` entry for your scheme. +4. Update `builtin/schemes.go` with an entry for your scheme (see existing + entries there for an example). diff --git a/scheme/example/corim.go b/scheme/example/corim.go new file mode 100644 index 00000000..a7468776 --- /dev/null +++ b/scheme/example/corim.go @@ -0,0 +1,30 @@ +// Copyright Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package + +import ( + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" +) + +const ProfileString = "" + +type TriplesValidator struct {} + +func (o *TriplesValidator) ValidTriples(triples *comid.Triples) error { + return nil // TODO +} + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + extMap := extensions.NewMap().Add(comid.ExtTriples, &TriplesValidator{}) + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/example/plugin/Makefile b/scheme/example/plugin/Makefile new file mode 100644 index 00000000..0989d164 --- /dev/null +++ b/scheme/example/plugin/Makefile @@ -0,0 +1,11 @@ +# Copyright Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +PLUGIN := ../../bin/scheme-.plugin +GOPKG := github.com/veraison/services/scheme/ +SRCS := main.go + +include ../../../mk/common.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/example/plugin/main.go b/scheme/example/plugin/main.go new file mode 100644 index 00000000..c7ac1d81 --- /dev/null +++ b/scheme/example/plugin/main.go @@ -0,0 +1,14 @@ +// Copyright Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "github.com/veraison/services/handler" + "github.com/veraison/services/plugin" + scheme "github.com/veraison/services/scheme/" +) + +func main() { + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) + plugin.Serve() +} diff --git a/scheme/example/scheme.go b/scheme/example/scheme.go new file mode 100644 index 00000000..385ff2df --- /dev/null +++ b/scheme/example/scheme.go @@ -0,0 +1,76 @@ +// Copyright Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package + +import ( + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" +) + +var Descriptor = handler.SchemeDescriptor{ + Name: "", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + }, + EvidenceMediaTypes: []string{ + "", + }, +} + +type Implementation struct{ + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), + } +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + return nil, nil // TODO +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + return nil, nil // TODO +} + +func (o *Implementation) ValidateComid(c *comid.Comid) error { + return nil // TODO +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + return nil, nil // TODO +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + return nil // TODO +} + +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + appraisal := result.Submods[Descriptor.Name] + // TODO + return result, nil +} diff --git a/scheme/nvidia-coserv/coserv_handler.go b/scheme/nvidia-coserv/coserv_handler.go index aa502e4a..e0436f6c 100644 --- a/scheme/nvidia-coserv/coserv_handler.go +++ b/scheme/nvidia-coserv/coserv_handler.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package nvidiacoserv @@ -44,8 +44,8 @@ func (s CoservProxyHandler) GetAttestationScheme() string { return SchemeName } -func (s CoservProxyHandler) GetSupportedMediaTypes() []string { - return CoservMediaTypes +func (s CoservProxyHandler) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{"coserv": CoservMediaTypes} } func callRimService(rimid *string) (*RimServiceResponse, error) { diff --git a/scheme/nvidia-coserv/plugin/Makefile b/scheme/nvidia-coserv/plugin/Makefile index 1d04f067..41edc8c8 100644 --- a/scheme/nvidia-coserv/plugin/Makefile +++ b/scheme/nvidia-coserv/plugin/Makefile @@ -1,11 +1,11 @@ # Copyright 2025 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += coserv-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/coserv-nvidia.plugin +GOPKG := github.com/veraison/services/scheme/nvidia-coserv +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/nvidia-coserv/plugin/combined/Makefile b/scheme/nvidia-coserv/plugin/combined/Makefile deleted file mode 100644 index eb9e44cf..00000000 --- a/scheme/nvidia-coserv/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/nvidia-coserv.plugin -GOPKG := github.com/veraison/services/scheme/nvidia-coserv -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/nvidia-coserv/plugin/coserv-handler/Makefile b/scheme/nvidia-coserv/plugin/coserv-handler/Makefile deleted file mode 100644 index ebca1b20..00000000 --- a/scheme/nvidia-coserv/plugin/coserv-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/nvidia-coserv-handler.plugin -GOPKG := github.com/veraison/services/scheme/nvidia-coserv -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/nvidia-coserv/plugin/coserv-handler/main.go b/scheme/nvidia-coserv/plugin/coserv-handler/main.go deleted file mode 100644 index c7316fec..00000000 --- a/scheme/nvidia-coserv/plugin/coserv-handler/main.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/nvidia-coserv" -) - -func main() { - handler.RegisterCoservProxyHandler(&scheme.CoservProxyHandler{}) - plugin.Serve() -} diff --git a/scheme/nvidia-coserv/plugin/combined/main.go b/scheme/nvidia-coserv/plugin/main.go similarity index 83% rename from scheme/nvidia-coserv/plugin/combined/main.go rename to scheme/nvidia-coserv/plugin/main.go index c7316fec..b5ee6c78 100644 --- a/scheme/nvidia-coserv/plugin/combined/main.go +++ b/scheme/nvidia-coserv/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main diff --git a/scheme/parsec-cca/Makefile b/scheme/parsec-cca/Makefile index 9f1c81d1..ec4f7f02 100644 --- a/scheme/parsec-cca/Makefile +++ b/scheme/parsec-cca/Makefile @@ -1,6 +1,5 @@ -# Copyright 2023 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 - .DEFAULT_GOAL := test GOPKG := github.com/veraison/services/scheme/parsec-cca diff --git a/scheme/parsec-cca/corim.go b/scheme/parsec-cca/corim.go new file mode 100644 index 00000000..d6a847c2 --- /dev/null +++ b/scheme/parsec-cca/corim.go @@ -0,0 +1,37 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package parsec_cca + +import ( + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + arm_cca "github.com/veraison/services/scheme/arm-cca" + "github.com/veraison/services/scheme/common" +) + +const ProfileString = "tag:github.com/parallaxsecond,2023-03-03:cca" + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + validator := &common.TriplesValidator{ + TAEnviromentValidator: func(e *comid.Environment) error { + return arm_cca.ValidatePlatformEnvironment(e, true) + }, + RefValEnviromentValidator: func(e *comid.Environment) error { + return arm_cca.ValidatePlatformEnvironment(e, false) + }, + CryptoKeysValidator: arm_cca.ValidateCryptoKeys, + MeasurementsValidator: arm_cca.ValidatePlatformMeasurements, + } + + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/parsec-cca/corim_test.go b/scheme/parsec-cca/corim_test.go new file mode 100644 index 00000000..3bd5c38a --- /dev/null +++ b/scheme/parsec-cca/corim_test.go @@ -0,0 +1,20 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package parsec_cca + +import ( + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "ok", + Input: corimParsecCcaValid, + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/parsec-cca/corim_test_vectors.go b/scheme/parsec-cca/corim_test_vectors.go deleted file mode 100644 index 4a6a62ef..00000000 --- a/scheme/parsec-cca/corim_test_vectors.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2023-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package parsec_cca - -import _ "embed" - -var ( - //go:embed test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor - unsignedCorimComidParsecCcaRefValOne []byte - - //go:embed test/corim/unsignedCorimParsecCcaComidParsecCcaMultRefVal.cbor - unsignedCorimComidParsecCcaMultRefVal []byte -) diff --git a/scheme/parsec-cca/endorsement_handler.go b/scheme/parsec-cca/endorsement_handler.go deleted file mode 100644 index 36bf4ded..00000000 --- a/scheme/parsec-cca/endorsement_handler.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "errors" - "mime" - - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common" -) - -type EndorsementHandler struct{} - -func (o EndorsementHandler) Init(params handler.EndorsementHandlerParams) error { - return nil // no-op -} - -func (o EndorsementHandler) Close() error { - return nil // no-op -} - -func (o EndorsementHandler) GetName() string { - return "corim (Parsec CCA profile)" -} - -func (o EndorsementHandler) GetAttestationScheme() string { - return SchemeName -} - -func (o EndorsementHandler) GetSupportedMediaTypes() []string { - return EndorsementMediaTypes -} - -func (o EndorsementHandler) Decode(data []byte, mediaType string, caCertPool []byte) (*handler.EndorsementHandlerResponse, error) { - extractor := &ParsecCcaExtractor{} - - if mediaType != "" { - mt, _, err := mime.ParseMediaType(mediaType) - if err != nil { - return nil, err - } - - // Use signed decoder for signed CoRIM - if mt == "application/rim+cose" { - return common.SignedCorimDecoder(data, extractor, caCertPool) - } - } - - // Default to unsigned CoRIM decoder - return common.UnsignedCorimDecoder(data, extractor) -} - -func (o EndorsementHandler) CoservRepackage(coservQuery string, resultSet []string) ([]byte, error) { - return nil, errors.New("Parsec CCA CoservRepackage not implemented") -} diff --git a/scheme/parsec-cca/endorsement_handler_test.go b/scheme/parsec-cca/endorsement_handler_test.go deleted file mode 100644 index 16be68fc..00000000 --- a/scheme/parsec-cca/endorsement_handler_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2023-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDecoder_Decode_OK(t *testing.T) { - tvs := [][]byte{ - unsignedCorimComidParsecCcaRefValOne, - unsignedCorimComidParsecCcaMultRefVal, - } - - d := &EndorsementHandler{} - - for _, tv := range tvs { - _, err := d.Decode(tv, "", nil) - assert.NoError(t, err) - } -} - -func TestDecoder_GetAttestationScheme(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetAttestationScheme() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetSupportedMediaTypes(t *testing.T) { - d := &EndorsementHandler{} - - expected := EndorsementMediaTypes - - actual := d.GetSupportedMediaTypes() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_Init(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Init(nil)) -} - -func TestDecoder_Close(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Close()) -} - -func TestDecoder_GetName_ok(t *testing.T) { - d := &EndorsementHandler{} - expectedName := "corim (Parsec CCA profile)" - name := d.GetName() - assert.Equal(t, name, expectedName) -} - -func TestDecoder_Decode_empty_data(t *testing.T) { - d := &EndorsementHandler{} - - emptyData := []byte{} - - expectedErr := `empty data` - - _, err := d.Decode(emptyData, "", nil) - - assert.EqualError(t, err, expectedErr) -} - -func TestDecoder_Decode_invalid_data(t *testing.T) { - d := &EndorsementHandler{} - - invalidCbor := []byte("invalid CBOR") - - expectedErr := `CBOR decoding failed` - - _, err := d.Decode(invalidCbor, "", nil) - - assert.ErrorContains(t, err, expectedErr) -} diff --git a/scheme/parsec-cca/evidence_handler.go b/scheme/parsec-cca/evidence_handler.go deleted file mode 100644 index 8d47431b..00000000 --- a/scheme/parsec-cca/evidence_handler.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "encoding/base64" - "encoding/json" - "errors" - "fmt" - - cca_platform "github.com/veraison/ccatoken/platform" - "github.com/veraison/ear" - "github.com/veraison/go-cose" - parsec_cca "github.com/veraison/parsec/cca" - "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" -) - -const ( - ScopeTrustAnchor = "trust anchor" - ScopeRefValues = "ref values" -) - -type EvidenceHandler struct{} - -func (s EvidenceHandler) GetName() string { - return "parsec-cca-evidence-handler" -} - -func (s EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func (s EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - var ( - evidence parsec_cca.Evidence - claimsSet = make(map[string]interface{}) - kat = make(map[string]interface{}) - ) - - if err := evidence.FromCBOR(token.Data); err != nil { - return nil, handler.BadEvidence(err) - } - kat["nonce"] = *evidence.Kat.Nonce - key := evidence.Kat.Cnf.COSEKey - ck, err := key.MarshalCBOR() - if err != nil { - return nil, handler.BadEvidence(err) - } - - kat["akpub"] = base64.StdEncoding.EncodeToString(ck) - - claimsSet["kat"] = kat - - pmap, err := common.ClaimsToMap(common.CcaPlatformWrapper{evidence.Pat.PlatformClaims}) // nolint:govet - if err != nil { - return nil, handler.BadEvidence(err) - } - claimsSet["cca.platform"] = pmap - rmap, err := common.ClaimsToMap(common.CcaRealmWrapper{evidence.Pat.RealmClaims}) // nolint:govet - if err != nil { - return nil, handler.BadEvidence(err) - } - claimsSet["cca.realm"] = rmap - - return claimsSet, nil -} - -func (s EvidenceHandler) ValidateEvidenceIntegrity(token *proto.AttestationToken, trustAnchors []string, endorsements []string) error { - var ( - evidence parsec_cca.Evidence - ) - - if err := evidence.FromCBOR(token.Data); err != nil { - return handler.BadEvidence(err) - } - - pk, err := arm.GetPublicKeyFromTA(SchemeName, trustAnchors[0]) - if err != nil { - return fmt.Errorf("could not get public key from trust anchor: %w", err) - } - - if err = evidence.Verify(pk); err != nil { - return fmt.Errorf("failed to verify signature: %w", err) - } - log.Debug("Parsec CCA token signature, verified") - return nil -} - -func (s EvidenceHandler) AppraiseEvidence( - ec *proto.EvidenceContext, endorsementsStrings []string, -) (*ear.AttestationResult, error) { - var endorsements []handler.Endorsement // nolint:prealloc - - result := handler.CreateAttestationResult(SchemeName) - - for i, e := range endorsementsStrings { - var endorsement handler.Endorsement - - if err := json.Unmarshal([]byte(e), &endorsement); err != nil { - return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err) - } - - endorsements = append(endorsements, endorsement) - } - - err := populateAttestationResult(result, ec.Evidence.AsMap(), endorsements) - return result, err -} - -func populateAttestationResult( - result *ear.AttestationResult, - evidence map[string]interface{}, - endorsements []handler.Endorsement, -) error { - appraisal := result.Submods[SchemeName] - - // once the signature on the token is verified, we can claim the HW is - // authentic - appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim - kmap, ok := evidence["kat"] - if !ok { - return handler.BadEvidence(errors.New("no key attestation map in the evidence")) - } - kat := kmap.(map[string]interface{}) - - key, ok := kat["akpub"] - if !ok { - return handler.BadEvidence(errors.New("no key in the evidence")) - } - var COSEKey cose.Key - - kb, err := base64.StdEncoding.DecodeString(key.(string)) - if err != nil { - return handler.BadEvidence(err) - } - err = COSEKey.UnmarshalCBOR(kb) - if err != nil { - return handler.BadEvidence(err) - } - // Extract Public Key and set the Veraison Extension - pk, err := COSEKey.PublicKey() - if err != nil { - return handler.BadEvidence(err) - } - - if err := appraisal.SetKeyAttestation(pk); err != nil { - return fmt.Errorf("setting extracted public key: %w", err) - } - - cp, ok := evidence["cca.platform"] - if !ok { - return handler.BadEvidence(errors.New("no cca platform in the evidence")) - } - pmap := cp.(map[string]interface{}) - claims, err := common.MapToCCAPlatformClaims(pmap) - if err != nil { - return handler.BadEvidence(err) - } - - rawLifeCycle, err := claims.GetSecurityLifeCycle() - if err != nil { - return handler.BadEvidence(err) - } - - lifeCycle := cca_platform.LifeCycleToState(rawLifeCycle) - if lifeCycle == cca_platform.StateSecured || - lifeCycle == cca_platform.StateNonCCAPlatformDebug { - 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 - } - - swComps := arm.FilterRefVal(endorsements, "platform.sw-component") - match := arm.MatchSoftware(SchemeName, claims, swComps) - if match { - appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim - log.Debug("matchSoftware Success") - - } else { - appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim - log.Debug("matchSoftware Failed") - } - - platformConfig := arm.FilterRefVal(endorsements, "platform.config") - match = arm.MatchPlatformConfig(SchemeName, claims, platformConfig) - - if match { - appraisal.TrustVector.Configuration = ear.ApprovedConfigClaim - log.Debug("matchPlatformConfig Success") - - } else { - appraisal.TrustVector.Configuration = ear.UnsafeConfigClaim - log.Debug("matchPlatformConfig Failed") - } - appraisal.UpdateStatusFromTrustVector() - - appraisal.VeraisonAnnotatedEvidence = &evidence - return nil -} diff --git a/scheme/parsec-cca/evidence_handler_test.go b/scheme/parsec-cca/evidence_handler_test.go deleted file mode 100644 index 5c92cd8a..00000000 --- a/scheme/parsec-cca/evidence_handler_test.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "encoding/json" - "errors" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/ear" - "github.com/veraison/services/proto" -) - -func Test_ExtractClaims_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - } - - ta := string(taEndValBytes) - _, err = handler.ExtractClaims(&token, []string{ta}) - require.NoError(t, err) -} - -func Test_ExtractClaims_nok_bad_evidence(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/bad_evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - expectedErr := "CBOR decoding: cbor: invalid additional information 28 for type byte string" - h := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - } - ta := string(taEndValBytes) - _, err = h.ExtractClaims(&token, []string{ta}) - err1 := errors.Unwrap(err) - require.NotNil(t, err1) - assert.EqualError(t, err1, expectedErr) -} - -func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - h := &EvidenceHandler{} - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - ta := string(taEndValBytes) - err = h.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - require.NoError(t, err) -} - -func Test_ValidateEvidenceIntegrity_nok(t *testing.T) { - tvs := []struct { - desc string - input string - expectedErr string - }{ - { - desc: "incorrect public key", - input: "test/evidence/unmatched_endorsements.json", - expectedErr: `failed to verify signature: PAT validation failed: unable to verify platform token: verification error`, - }, - { - desc: "invalid public key", - input: "test/evidence/bad_key_endorsements.json", - expectedErr: `could not get public key from trust anchor: could not decode subject public key info: unable to parse public key: asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:1 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} AlgorithmIdentifier @2`, - }, - { - desc: "bad pem key header", - input: "test/evidence/bad_key_header_endorsements.json", - expectedErr: `could not get public key from trust anchor: could not decode subject public key info: could not extract trust anchor PEM block`, - }, - { - desc: "incorrect key type", - input: "test/evidence/bad_key_private_key.json", - expectedErr: "could not get public key from trust anchor: could not decode subject public key info: unsupported key type: \"PRIVATE KEY\"", - }, - } - - for _, tv := range tvs { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile(tv.input) - ta := string(taEndValBytes) - require.NoError(t, err) - h := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - - err = h.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - assert.EqualError(t, err, tv.expectedErr) - } -} - -func Test_AppraiseEvidence_mismatch(t *testing.T) { - tvs := []struct { - desc string - input string - }{ - { - desc: "mismatch platform config", - input: "test/evidence/mismatch_cfg_refval_endorsements.json", - }, - { - desc: "mismatch SW Components", - input: "test/evidence/mismatch_swcomp_refval_endorsements.json", - }, - } - - for index, tv := range tvs { - var endorsemementsArray []string - extractedBytes, err := os.ReadFile("test/evidence/extracted.json") - require.NoError(t, err) - - var ec proto.EvidenceContext - err = json.Unmarshal(extractedBytes, &ec) - require.NoError(t, err) - endorsementsBytes, err := os.ReadFile(tv.input) - require.NoError(t, err) - err = json.Unmarshal(endorsementsBytes, &endorsemementsArray) - require.NoError(t, err) - - handler := &EvidenceHandler{} - - result, err := handler.AppraiseEvidence(&ec, endorsemementsArray) - require.NoError(t, err) - attestation := result.Submods["PARSEC_CCA"] - - assert.Equal(t, ear.TrustTierWarning, *attestation.Status) - if index == 0 { - assert.Equal(t, attestation.TrustVector.Executables, ear.ApprovedRuntimeClaim) - assert.Equal(t, attestation.TrustVector.Configuration, ear.UnsafeConfigClaim) - } else { - assert.Equal(t, attestation.TrustVector.Executables, ear.UnrecognizedRuntimeClaim) - assert.Equal(t, attestation.TrustVector.Configuration, ear.ApprovedConfigClaim) - } - - } -} - -func Test_AppraiseEvidence_ok(t *testing.T) { - var endorsemementsArray []string - extractedBytes, err := os.ReadFile("test/evidence/extracted.json") - require.NoError(t, err) - - var ec proto.EvidenceContext - err = json.Unmarshal(extractedBytes, &ec) - require.NoError(t, err) - endorsementsBytes, err := os.ReadFile("test/evidence/refval_endorsements.json") - require.NoError(t, err) - err = json.Unmarshal(endorsementsBytes, &endorsemementsArray) - require.NoError(t, err) - - handler := &EvidenceHandler{} - - result, err := handler.AppraiseEvidence(&ec, endorsemementsArray) - require.NoError(t, err) - attestation := result.Submods["PARSEC_CCA"] - - assert.Equal(t, ear.TrustTierAffirming, *attestation.Status) - assert.Equal(t, attestation.TrustVector.Executables, ear.ApprovedRuntimeClaim) - assert.Equal(t, attestation.TrustVector.Configuration, ear.ApprovedConfigClaim) -} - -func Test_GetName_ok(t *testing.T) { - scheme := &EvidenceHandler{} - expectedName := "parsec-cca-evidence-handler" - name := scheme.GetName() - assert.Equal(t, name, expectedName) -} - -func Test_GetAttestationScheme_ok(t *testing.T) { - scheme := &EvidenceHandler{} - expectedScheme := "PARSEC_CCA" - name := scheme.GetAttestationScheme() - assert.Equal(t, name, expectedScheme) -} - -func Test_GetSupportedMediaTypes_ok(t *testing.T) { - expectedMt := "application/vnd.parallaxsecond.key-attestation.cca" - scheme := &EvidenceHandler{} - mtList := scheme.GetSupportedMediaTypes() - assert.Len(t, mtList, 1) - assert.Equal(t, mtList[0], expectedMt) -} diff --git a/scheme/parsec-cca/parsec_cca_extractor.go b/scheme/parsec-cca/parsec_cca_extractor.go deleted file mode 100644 index cb052eb3..00000000 --- a/scheme/parsec-cca/parsec_cca_extractor.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common/cca/platform" -) - -type ParsecCcaExtractor struct { - Profile string -} - -func (o ParsecCcaExtractor) RefValExtractor( - rvs comid.ValueTriples, -) ([]*handler.Endorsement, error) { - if o.Profile != "tag:github.com/parallaxsecond,2023-03-03:cca" { - return nil, fmt.Errorf("invalid profile: %s for scheme PARSEC_CCA", o.Profile) - } - subScheme := &platform.CcaSsdExtractor{} - return subScheme.RefValExtractor(rvs) -} - -func (o ParsecCcaExtractor) TaExtractor(avk comid.KeyTriple) (*handler.Endorsement, error) { - if o.Profile != "tag:github.com/parallaxsecond,2023-03-03:cca" { - return nil, fmt.Errorf("invalid profile: %s for scheme PARSEC_CCA", o.Profile) - } - subScheme := &platform.CcaSsdExtractor{} - return subScheme.TaExtractor(avk) -} - -func (o *ParsecCcaExtractor) SetProfile(profile string) { - o.Profile = profile -} diff --git a/scheme/parsec-cca/plugin/Makefile b/scheme/parsec-cca/plugin/Makefile index b05ea59a..7cfe44a7 100644 --- a/scheme/parsec-cca/plugin/Makefile +++ b/scheme/parsec-cca/plugin/Makefile @@ -1,13 +1,11 @@ -# Copyright 2023 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += endorsement-handler - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-parsec-cca.plugin +GOPKG := github.com/veraison/services/scheme/parsec-cca +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk \ No newline at end of file +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/parsec-cca/plugin/combined/Makefile b/scheme/parsec-cca/plugin/combined/Makefile deleted file mode 100644 index c7f7e8a2..00000000 --- a/scheme/parsec-cca/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-cca.plugin -GOPKG := github.com/veraison/services/scheme/parsec-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-cca/plugin/combined/main.go b/scheme/parsec-cca/plugin/combined/main.go deleted file mode 100644 index 769fae7d..00000000 --- a/scheme/parsec-cca/plugin/combined/main.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/parsec-cca" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/parsec-cca/plugin/endorsement-handler/Makefile b/scheme/parsec-cca/plugin/endorsement-handler/Makefile deleted file mode 100644 index 2cdb836d..00000000 --- a/scheme/parsec-cca/plugin/endorsement-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-cca-endorsement-handler.plugin -GOPKG := github.com/veraison/services/scheme/parsec-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-cca/plugin/evidence-handler/Makefile b/scheme/parsec-cca/plugin/evidence-handler/Makefile deleted file mode 100644 index 640af3e9..00000000 --- a/scheme/parsec-cca/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-cca-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/parsec-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-cca/plugin/evidence-handler/main.go b/scheme/parsec-cca/plugin/evidence-handler/main.go deleted file mode 100644 index d4c6e019..00000000 --- a/scheme/parsec-cca/plugin/evidence-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/parsec-cca" -) - -func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - plugin.Serve() -} diff --git a/scheme/parsec-cca/plugin/endorsement-handler/main.go b/scheme/parsec-cca/plugin/main.go similarity index 61% rename from scheme/parsec-cca/plugin/endorsement-handler/main.go rename to scheme/parsec-cca/plugin/main.go index eaec6d36..4e504984 100644 --- a/scheme/parsec-cca/plugin/endorsement-handler/main.go +++ b/scheme/parsec-cca/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) plugin.Serve() } diff --git a/scheme/parsec-cca/plugin/store-handler/Makefile b/scheme/parsec-cca/plugin/store-handler/Makefile deleted file mode 100644 index ccfd3512..00000000 --- a/scheme/parsec-cca/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-cca-store-handler.plugin -GOPKG := github.com/veraison/services/scheme/parsec-cca -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-cca/plugin/store-handler/main.go b/scheme/parsec-cca/plugin/store-handler/main.go deleted file mode 100644 index 7f57556c..00000000 --- a/scheme/parsec-cca/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/parsec-cca" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/parsec-cca/scheme.go b/scheme/parsec-cca/scheme.go index 64f14ec7..e313fe40 100644 --- a/scheme/parsec-cca/scheme.go +++ b/scheme/parsec-cca/scheme.go @@ -1,19 +1,198 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package parsec_cca -const ( - SchemeName = "PARSEC_CCA" - EndorsementProfile = `"tag:github.com/parallaxsecond,2023-03-03:cca"` +import ( + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/go-cose" + parsec_cca "github.com/veraison/parsec/cca" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + cca_scheme "github.com/veraison/services/scheme/arm-cca" + "github.com/veraison/services/scheme/common" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" ) -var EndorsementMediaTypes = []string{ - // Unsigned CoRIM profile - `application/corim-unsigned+cbor; profile=` + EndorsementProfile, - // Signed CoRIM profile - `application/rim+cose; profile=` + EndorsementProfile, +var Descriptor = handler.SchemeDescriptor{ + Name: "PARSEC_CCA", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + }, + EvidenceMediaTypes: []string{ + "application/vnd.parallaxsecond.key-attestation.cca", + }, +} + +type Implementation struct { + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), + } +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + var parsecEvidence parsec_cca.Evidence + + err := parsecEvidence.FromCBOR(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + implIDbytes, err := parsecEvidence.Pat.PlatformClaims.GetImplID() + if err != nil { + return nil, err + } + + instIDbytes, err := parsecEvidence.Pat.PlatformClaims.GetInstID() + if err != nil { + return nil, err + } + + classID, err := comid.NewImplIDClassID(implIDbytes) + if err != nil { + return nil, err + } + + instanceID, err := comid.NewUEIDInstance(instIDbytes) + if err != nil { + return nil, err + } + + return []*comid.Environment{ + { + Class: &comid.Class{ClassID: classID}, + Instance: instanceID, + }, + }, nil +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + numTAs := len(trustAnchors) + if numTAs != 1 { + return nil, fmt.Errorf("expected exactly 1 trust anchor; got %d", numTAs) + } + + return []*comid.Environment{ + { + Class: trustAnchors[0].Environment.Class, + }, + }, nil +} + +func (o *Implementation) ValidateComid(c *comid.Comid) error { + return nil +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + var parsecEvidence parsec_cca.Evidence + + err := parsecEvidence.FromCBOR(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + ck, err := parsecEvidence.Kat.Cnf.COSEKey.MarshalCBOR() + if err != nil { + return nil, handler.BadEvidence(err) + } + + katClaims := map[string]any{ + "nonce": parsecEvidence.Kat.Nonce.GetI(0), + "akpub": ck, + } + + platformClaims, err := common.ToMapViaJSON(parsecEvidence.Pat.PlatformClaims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + realmClaims, err := common.ToMapViaJSON(parsecEvidence.Pat.RealmClaims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + claims := map[string]any{ + "kat": katClaims, + "cca.platform": platformClaims, + "cca.realm": realmClaims, + } + + return claims, nil +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + var parsecEvidence parsec_cca.Evidence + + err := parsecEvidence.FromCBOR(evidence.Data) + if err != nil { + return handler.BadEvidence(err) + } + + pk, err := common.ExtractPublicKeyFromTrustAnchors(trustAnchors) + if err != nil { + return fmt.Errorf("could not get public key from trust anchors: %w", err) + } + + if err = parsecEvidence.Verify(pk); err != nil { + return handler.BadEvidence("failed to verify signature: %w", err) + } + + o.logger.Debug("Parsec CCA token signature verified") + return nil } -var EvidenceMediaTypes = []string{ - "application/vnd.parallaxsecond.key-attestation.cca", +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + appraisal := result.Submods[Descriptor.Name] + + // once the signature on the token is verified, we can claim the HW is + // authentic + appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim + + katClaims := claims["kat"].(map[string]any) + + var coseKey cose.Key + if err := coseKey.UnmarshalCBOR(katClaims["akpub"].([]byte)); err != nil { + return result, handler.BadEvidence(err) + } + + pk, err := coseKey.PublicKey() + if err != nil { + return result, handler.BadEvidence(err) + } + + if err := appraisal.SetKeyAttestation(pk); err != nil { + return result, fmt.Errorf("setting extracted public key: %w", err) + } + + err = cca_scheme.AppraisePlatform(o.logger, appraisal, claims["cca.platform"], endorsements) + if err != nil { + return result, err + } + + return result, nil } diff --git a/scheme/parsec-cca/store_handler.go b/scheme/parsec-cca/store_handler.go deleted file mode 100644 index 8af8cbe5..00000000 --- a/scheme/parsec-cca/store_handler.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2024-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "fmt" - - parsec_cca "github.com/veraison/parsec/cca" - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" - "github.com/veraison/services/scheme/common/arm" -) - -type StoreHandler struct{} - -func (s StoreHandler) GetName() string { - return "parsec-cca-store-handler" -} - -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -func (s StoreHandler) SynthKeysFromRefValue( - tenantID string, - refVal *handler.Endorsement, -) ([]string, error) { - - return arm.SynthKeysForPlatform(SchemeName, tenantID, refVal) -} - -func (s StoreHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) { - - return arm.SynthKeysFromTrustAnchors(SchemeName, tenantID, ta) -} - -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - var evidence parsec_cca.Evidence - - err := evidence.FromCBOR(token.Data) - if err != nil { - return []string{""}, handler.BadEvidence(err) - } - claims := evidence.Pat.PlatformClaims - - taID, err := arm.GetTrustAnchorID(SchemeName, token.TenantId, claims) - if err != nil { - return []string{""}, err - } - - return []string{taID}, nil -} - -func (s StoreHandler) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - platformClaimsMap, ok := claims["cca.platform"].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("claims do not contain platform map: %v", claims) - } - return arm.GetPlatformReferenceIDs(SchemeName, tenantID, platformClaimsMap) -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - return []string{"TODO"}, nil -} diff --git a/scheme/parsec-cca/store_handler_test.go b/scheme/parsec-cca/store_handler_test.go deleted file mode 100644 index 3c65c0f0..00000000 --- a/scheme/parsec-cca/store_handler_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_cca - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -func Test_GetTrustAnchorIDs_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - - expectedTaID := "PARSEC_CCA://1/f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=/AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY" - - handler := &StoreHandler{} - - taIDs, err := handler.GetTrustAnchorIDs(&token) - require.NoError(t, err) - assert.Equal(t, expectedTaID, taIDs[0]) -} - -func Test_GetRefValueIDs_ok(t *testing.T) { - rawToken, err := os.ReadFile("test/evidence/extracted.json") - require.NoError(t, err) - - tokenJSON := make(map[string]interface{}) - err = json.Unmarshal(rawToken, &tokenJSON) - require.NoError(t, err) - - claims := tokenJSON["evidence"].(map[string]interface{}) - - expectedRefvalIDs := []string{"PARSEC_CCA://1/f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA="} - - scheme := &StoreHandler{} - refvalIDs, err := scheme.GetRefValueIDs("1", nil, claims) - require.NoError(t, err) - assert.Equal(t, expectedRefvalIDs, refvalIDs) -} - -func Test_SynthKeysFromTrustAnchor_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "PARSEC_CCA://1/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=/Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromTrustAnchor("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) - -} - -func Test_SynthKeysFromRefValue_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/evidence/refval_endorsement.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "PARSEC_CCA://1/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromRefValue("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) -} diff --git a/scheme/parsec-cca/test/corim/build-test-vectors.sh b/scheme/parsec-cca/test/corim/build-test-vectors.sh deleted file mode 100755 index 839baf6a..00000000 --- a/scheme/parsec-cca/test/corim/build-test-vectors.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -set -eu -set -o pipefail - -THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -GEN_CORIM="$THIS_DIR/../../../common/scripts/gen-corim" - -CORIM_TEMPLATE=corimParsecCca - -COMID_TEMPLATES=( - ComidParsecCcaRefValOne - ComidParsecCcaMultRefVal -) - -for comid in "${COMID_TEMPLATES[@]}" -do - "$GEN_CORIM" "$THIS_DIR" "$comid" "$CORIM_TEMPLATE" "unsigned" -done - -echo "done" diff --git a/scheme/parsec-cca/test/corim/compile-endorsements.sh b/scheme/parsec-cca/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..d9f7837f --- /dev/null +++ b/scheme/parsec-cca/test/corim/compile-endorsements.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p parsec_cca "$THIS_DIR"/corim-*.cbor diff --git a/scheme/parsec-cca/test/corim/corim-parsec-cca-valid.cbor b/scheme/parsec-cca/test/corim/corim-parsec-cca-valid.cbor new file mode 100644 index 0000000000000000000000000000000000000000..f8555f88c25789559c87490f804dbcadf93728f0 GIT binary patch literal 960 zcmcb~_;oQug{lD*=z?enVV0bn2xh_L3>lklGX9EWVpzhEnwqEU?!>r|A;5X}<9fYB zZ{u~BgU^3->K0>aT+EQ^=0tiy4!gd{|PA^-T1PSR)kJ*;rYanHU-P`FMG_ zxi~q*#Y9Dfg#-oUGuzjYCDl;RNY8)-v$+Yl0dBSt#B5^{ z%;qQ7Y-5nw1|+##m{e`U46ZsoJ0IPlf6TOT{1Hb4J(6-jZKZrGF_r99Jw+> z^36j^&AbB~3(L%1%+rI7A_~0RlA2!low~)C8W%HUIy(EhD)^M7=rP_yO{Rzlg?d*XHzr0#1{h#wuwwx60wN$Hj42>fnX-cN6H|gp^YT)Q zS{DIzMlNPda`ItGHP$oHGh&TUU}s}xVP;}v;OFDz;pXDx5El~_5f%~@ke8E{k(QE_ zU|h)5*u+R!9n5TBLzZMi+L&y_k_t3g&zKgjHfBjQq_VkDS;=YX3T1|R26_gJ3t4V5 z8AK>D5(;jn#zhP_6e=8GiJ%~{C^fGHmJIZZGINXdlarH-6B8{=b6s-NrAd0p`MLT)>k@Nv5-W;Rlk@XZbc_s)jCBn_$SOHGk!2CXL8-)Z X9t?~Jr7}a(8(7hkZVpP4ZDa%h^xCq* diff --git a/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor b/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor deleted file mode 100644 index f9aa8ed3a96fc127ee886d2dcc5bb1cf911d00bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411 zcmcb~_;ndWKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9AHZEaEP0iDFcVb+~5a7J~alKxm zxAD5m!RJ3Zb&D}IE@sGdboO;s@F_{rW4xhIl2KApP;8~IpO~DRs+U@km|KvO%GAuj z$i%Xcp|NQp!(xV;Oc46c{q5fJ|k|3d&DR2`bIY zOD$?#1k@Rom7JEYP-duSpl86ikmV+mK~Pa*d0ApkX(|_-!30!#L!rU}=9GfOBA^{G z$LJSj<`(NGCnp&vCR&*4ni(dU=$aU$8R}Y?SfuJ27$v5drCKB!nVKXqHZevhJc%y) zdf>p;qT9Z`R@-0JoArP9OERfy@_na(=Ep(7ME& zoWzRa)a3lU6dfZ2BV%0y5VA^6PGnica8N4ooCgErL8;7;^afV+0L(!NxJE_*(XNz| diff --git a/scheme/parsec-cca/test/evidence/bad_evidence.cbor b/scheme/parsec-cca/test/evidence/bad_evidence.cbor deleted file mode 100644 index fe79c66d9fbcad5f1b4853d70448174559c9eb2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 655 zcmZ3KoSj&*EUlydan1ti{$Lg zln6z}6&ylGc@m5Z%cClT9x!nEcuIbX|F&Hu{g;tT;Nb$E^z?$#B*&uE#E1w6WuV0@ z3`GnK3<6+BFav3Y>qgJxbeRfRba>j87ac7YW##*y+}qjdb+<%q-??knbqoqlw_0^o z_wANgdW?5wNQ3O2Q;rgLTT=vsEi-HUj;~zIn30@XRN|SJmLDrBJlBJ+12um$WHo_7QXL+x^z43YR zv%j^|&(~Mpytq8bBfybMEUZ#x&V`(fhL;!=1iuFGmd$&#L2u>ii8C%HH?TYKTspk( Y /dev/null && pwd ) +SRC_DIR="$THIS_DIR/src" +BUILD_DIR="$THIS_DIR/__build" + +rm -rf "$BUILD_DIR" +mkdir -p "$BUILD_DIR" + +diag2cbor.rb < "$SRC_DIR/kat.diag" > "$BUILD_DIR/kat.cbor" + +KAT_HASH=$(sha512sum "$BUILD_DIR/kat.cbor" | cut -f1 -d" " | xxd -p -r | base64 -w0) +export KAT_HASH + +envsubst < "$SRC_DIR/cca-claims.json.template" > "$BUILD_DIR/cca-claims.json" + +evcli cca create --iak="$SRC_DIR/ec.p256.jwk" --rak="$SRC_DIR/ec.p384.jwk" \ + --claims="$BUILD_DIR/cca-claims.json" --token="$BUILD_DIR/cca-token.cbor" + +# a2 -- map(2) +# 63 -- tstr(3) 63 -- tstr(3) +# 6b6174 -- "kat" 706174 -- "pat" +echo "a2636b6174$(xxd -p < "$BUILD_DIR/kat.cbor")63706174$(xxd -p < "$BUILD_DIR/cca-token.cbor")" | \ + xxd -p -r > evidence.cbor diff --git a/scheme/parsec-cca/test/evidence/evidence.cbor b/scheme/parsec-cca/test/evidence/evidence.cbor old mode 100755 new mode 100644 index 08c82aebccd7972491cbc11b0e444f5b4e55baf7..b237522880c931bc27ce28e58d63705820d55084 GIT binary patch literal 1494 zcmZ3KoSj&5lPPi$mj?qQ6Eh1d8#~8B#wCnQ3XF;o3bX&;URG+XGkbUJqfNIse@M7{ z&6stFLHUQq!6fb#{E0V|A{0(o9x5`p&p5;3@{*Wo68XLCl6HHXS2#Yn`{+pWHyypU0CK_rv1k_HTtobfG77?YfQm?9L|*;rYanHU-P`FMG_xi~q*#Y9Df zg#-oUus|1?pYX~%vo1lq?dPaH%M4D&>G?AYu6OD;9(HLl= zFcBsKr+^g!`k42qlFSMD7ofb zgo87MKyuCb7RpT-9wtbxIRi^rl55UJWP{2%CdCMYrr#HhR&G5!t$qG(Q4`(?0n__J zkIxONT(paCYOBBbBc4m&{H=?&7VN%W{O-}YvKCdP2!pp@UEl8O{J;Le%j~^wj|x7q zPdnnVvvJ$Ck@l**?EkcUE%E1(?+l2}_U9uQoB;b*SNZ z?1c2MZ-reyAAa>Y=)Zz{+La2i`fEOF>5EjhYOX&}ynY#v=K|$#btg_RX*-neH~IO- r{LjYoJNGWP2)t4FMSgXtoZf@k*HpS!N;AdWxVie2Ua}BZdtMCyx6ib_ delta 678 zcmcb{y@P8)9?ybHEiMZgEtD2SG8s>-RQ29E-DX?&s`*DlBPz1%j@4&A;r+TRYNg^? z9`!G*?F$57Npi+SDAc?9xG^y@GQa>cgB=5i7Z3pvkz{0uP-L9^fl+}?k~0y?l$PX- zmNa0Nz!Z$TZo3Nwq$wJR`9r zwJfzrFF8LqBH`IK3;%WYdFfxTO!v0`%k@k4gMRUj|M5%*_#M`KUNm>BVSt$bFB4n7 z^$#vw%=s|)AfwYFn{!vZBJXH&8BC7fG9z)<;uWn|j6e6lFBhXO35aM2SFE7q?$89%W2UPYwc7N2}&%gf2TgPx{bSD!CfA-U#!%fy39aFi60u+As#%iPz0 z&#gUwVSZ^>`0H*J`7evBH190u=}G;k95-vqx{KFet}l4{S#R^wNeNQSVGI1LZ>{q9 v_w8ri)Ju07!zN9!al06n8_1J7 /dev/null && pwd ) + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession?nonce=byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA== 2>/dev/null | grep "Location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H "content-type: $EVIDENCE_CONTENT_TYPE" --data-binary @"$THIS_DIR/$EVIDENCE_FILE" https://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/parsec-cca/test/evidence/ta_endorsements.json b/scheme/parsec-cca/test/evidence/ta_endorsements.json deleted file mode 100644 index 9d996f02..00000000 --- a/scheme/parsec-cca/test/evidence/ta_endorsements.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scheme":"PARSEC_CCA", - "type":"VERIFICATION_KEY", - "attributes":{ - "hw-model":"RoadRunner", - "hw-vendor":"ACME", - "impl-id":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "iak-pub":"-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIShnxS4rlQiwpCCpBWDzlNLfqiG911FP\n8akBr+fh94uxHU5m+Kijivp2r2oxxN6MhM4tr8mWQli1P61xh3T0ViDREbF26DGO\nEYfbAjWjGNN7pZf+6A4OTHYqEryz6m7U\n-----END PUBLIC KEY-----", - "inst-id":"Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/unmatched_endorsements.json b/scheme/parsec-cca/test/evidence/unmatched_endorsements.json deleted file mode 100644 index 8ce00f9f..00000000 --- a/scheme/parsec-cca/test/evidence/unmatched_endorsements.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "scheme":"PARSEC_CCA", - "type":"VERIFICATION_KEY", - "attributes":{ - "hw-model":"RoadRunner", - "hw-vendor":"ACME", - "impl-id":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "iak-pub":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2lB1xtcIWePIt/Wwt+s8Ybp+5ji8\nt2pzGDKSOG7xTGK5gOYkcLCHz4i4L/yGzyEmBO1mZFZNuJz14X0J24+XQQ==\n-----END PUBLIC KEY-----", - "inst-id":"Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} - diff --git a/scheme/parsec-cca/test_vars.go b/scheme/parsec-cca/test_vars.go new file mode 100644 index 00000000..538e3c8a --- /dev/null +++ b/scheme/parsec-cca/test_vars.go @@ -0,0 +1,12 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package parsec_cca + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-parsec-cca-valid.cbor + corimParsecCcaValid []byte +) diff --git a/scheme/parsec-tpm/Makefile b/scheme/parsec-tpm/Makefile index 7aebf6d8..0113c10f 100644 --- a/scheme/parsec-tpm/Makefile +++ b/scheme/parsec-tpm/Makefile @@ -1,6 +1,5 @@ -# Copyright 2023 Contributors to the Veraison project. +# Copyright 2021 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 - .DEFAULT_GOAL := test GOPKG := github.com/veraison/services/scheme/parsec-tpm @@ -8,9 +7,6 @@ SRCS := $(wildcard *.go) SUBDIR += plugin -# auto-generated -COPYRIGHT_FLAGS += --ignore */corim_test_vectors.go - include ../../mk/common.mk include ../../mk/lint.mk include ../../mk/pkg.mk diff --git a/scheme/parsec-tpm/README.md b/scheme/parsec-tpm/README.md deleted file mode 100644 index 935127a5..00000000 --- a/scheme/parsec-tpm/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Endorsement Store Interface - -## Reference Value - -```json -{ - "scheme": "PARSEC_TPM", - "type": "REFERENCE_VALUE", - "attributes": { - "parsec-tpm.alg-id": 1, - "parsec-tpm.class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c", - "parsec-tpm.digest": "h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", - "parsec-tpm.pcr": 0 - } -} -``` - -## Trust Anchor - -```json -{ - "scheme": "PARSEC_TPM", - "type": "VERIFICATION_KEY", - "attributes": { - "parsec-tpm.ak-pub": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE_RwSXooI8DdatPOYg_uiKm2XrtT_uEMEvqQZrwJHHcfw0c3WVzGoqL3Y_Q6xkHFfdUVqS2WWkPdKO03uw==", - "parsec-tpm.class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c", - "parsec-tpm.instance-id": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - } -} -``` diff --git a/scheme/parsec-tpm/common.go b/scheme/parsec-tpm/common.go deleted file mode 100644 index 389246dc..00000000 --- a/scheme/parsec-tpm/common.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -const ( - ScopeTrustAnchor = "trust anchor" - ScopeRefValues = "ref values" -) - diff --git a/scheme/parsec-tpm/corim.go b/scheme/parsec-tpm/corim.go new file mode 100644 index 00000000..83cefe82 --- /dev/null +++ b/scheme/parsec-tpm/corim.go @@ -0,0 +1,103 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package parsec_tpm + +import ( + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/services/scheme/common" +) + +const ProfileString = "tag:github.com/parallaxsecond,2023-03-03:tpm" + +func validateEnvironment(env *comid.Environment, isTrustAnchor bool) error { + if env.Class == nil { + return errors.New("class not set in environment") + } + + if env.Class.ClassID == nil { + return errors.New("class ID not set in environment") + } + + if env.Class.ClassID.Type() != comid.UUIDType { + return fmt.Errorf("class ID: expected uuid, found %s", env.Class.ClassID.Type()) + } + + if isTrustAnchor { + if env.Instance == nil { + return errors.New("instance not set in trust anchor environment") + } + + if env.Instance.Type() != comid.BytesType { + return fmt.Errorf("instance: expected bytes, found %s", env.Instance.Type()) + } + } else if env.Instance != nil { + return errors.New("instance set in reference value environment") + } + + if env.Group != nil { + return errors.New("group set in environment") + } + + return nil +} + +func validateCryptoKeys(keys []*comid.CryptoKey) error { + if len(keys) != 1 { + return fmt.Errorf("expected exactly one key but got %d", len(keys)) + } + + if keys[0].Type() != comid.PKIXBase64KeyType { + return fmt.Errorf("trust anchor must be a PKIX base64 key, found: %s", keys[0].Type()) + } + + return nil +} + +func validateMeasurements(measurements []comid.Measurement) error { + for i, mea := range measurements { + if mea.Key == nil { + return fmt.Errorf("measurement %d has no key", i) + } + + if mea.Key.Type() != comid.UintType { + return fmt.Errorf("measurement %d key: expected uint, found %s", + i, mea.Key.Type()) + + } + + if mea.Val.Digests == nil { + return fmt.Errorf("measurement %d does not contain digests", i) + } + } + + return nil +} + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + validator := &common.TriplesValidator{ + TAEnviromentValidator: func(e *comid.Environment) error { + return validateEnvironment(e, true) + }, + RefValEnviromentValidator: func(e *comid.Environment) error { + return validateEnvironment(e, false) + }, + CryptoKeysValidator: validateCryptoKeys, + MeasurementsValidator: validateMeasurements, + } + + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/parsec-tpm/corim_extractor.go b/scheme/parsec-tpm/corim_extractor.go deleted file mode 100644 index 10fb8b76..00000000 --- a/scheme/parsec-tpm/corim_extractor.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/eat" - "github.com/veraison/services/handler" - "github.com/veraison/swid" -) - -type CorimExtractor struct{ Profile string } - -func (o CorimExtractor) RefValExtractor( - rvs comid.ValueTriples, -) ([]*handler.Endorsement, error) { - refVals := make([]*handler.Endorsement, 0, len(rvs.Values)) - for _, rv := range rvs.Values { - var id ID - if err := id.FromEnvironment(rv.Environment); err != nil { - return nil, fmt.Errorf( - "could not extract id from ref-val environment: %w", - err, - ) - } - for i, m := range rv.Measurements.Values { - var refval *handler.Endorsement - pcr, err := extractPCR(m) - if err != nil { - return nil, fmt.Errorf("could not extract PCR: %w", err) - } - - digests, err := extractDigests(m) - if err != nil { - return nil, fmt.Errorf("measurement[%d]: %w", i, err) - } - - for j, digest := range digests { - attrs, err := makeRefValAttrs(id.class, pcr, digest) - if err != nil { - return nil, fmt.Errorf("measurement[%d].digest[%d]: %w", i, j, err) - } - - refval = &handler.Endorsement{ - Scheme: SchemeName, - Type: handler.EndorsementType_REFERENCE_VALUE, - Attributes: attrs, - } - } - refVals = append(refVals, refval) - } - } - - if len(refVals) == 0 { - return nil, fmt.Errorf("no measurements found") - } - - return refVals, nil -} - -func (o CorimExtractor) TaExtractor( - avk comid.KeyTriple, -) (*handler.Endorsement, error) { - var id ID - - if err := id.FromEnvironment(avk.Environment); err != nil { - return nil, fmt.Errorf("could not extract id from AVK environment: %w", err) - } - - if len(avk.VerifKeys) != 1 { - return nil, errors.New("expecting exactly one AK public key") - } - - // Key can't be empty/nil -- the corim decoder is validating this - akPub := avk.VerifKeys[0] - if _, ok := akPub.Value.(*comid.TaggedPKIXBase64Key); !ok { - return nil, fmt.Errorf("ak-pub does not appear to be a PEM key (%T)", akPub.Value) - } - - taAttrs, err := makeTaAttrs(id, akPub) - if err != nil { - return nil, fmt.Errorf("failed to create trust anchor raw public key: %w", err) - } - - ta := &handler.Endorsement{ - Scheme: SchemeName, - Type: handler.EndorsementType_VERIFICATION_KEY, - Attributes: taAttrs, - } - - return ta, nil -} - -func makeRefValAttrs(class string, pcr uint64, digest swid.HashEntry) (json.RawMessage, error) { - - var attrs = map[string]interface{}{ - "parsec-tpm.class-id": class, - "parsec-tpm.pcr": pcr, - "parsec-tpm.digest": digest.HashValue, - "parsec-tpm.alg-id": digest.HashAlgID, - } - data, err := json.Marshal(attrs) - if err != nil { - return nil, fmt.Errorf("unable to marshal reference value attributes: %w", err) - } - return data, nil -} - -func makeTaAttrs(id ID, key *comid.CryptoKey) (json.RawMessage, error) { - if id.instance == nil { - return nil, errors.New("instance not found in ID") - } - - attrs := map[string]interface{}{ - "parsec-tpm.class-id": id.class, - "parsec-tpm.instance-id": []byte(*id.instance), - "parsec-tpm.ak-pub": key.String(), - } - - data, err := json.Marshal(attrs) - if err != nil { - return nil, fmt.Errorf("unable to marshal trust anchor attributes: %w", err) - } - return data, nil -} - -func extractPCR(m comid.Measurement) (uint64, error) { - if m.Key == nil { - return comid.MaxUint64, fmt.Errorf("measurement key is not present") - } - - if !m.Key.IsSet() { - return comid.MaxUint64, fmt.Errorf("measurement key is not set") - } - - pcr, err := m.Key.GetKeyUint() - if err != nil { - return 0, fmt.Errorf("measurement key is not uint: %w", err) - } - - return pcr, nil -} - -func extractDigests(m comid.Measurement) ([]swid.HashEntry, error) { - if m.Val.Digests == nil { - return nil, fmt.Errorf("measurement value does not contain digests") - } - - return *m.Val.Digests, nil -} - -type ID struct { - class string - instance *eat.UEID -} - -func (o *ID) FromEnvironment(e comid.Environment) error { - if e.Instance != nil { - i, err := e.Instance.GetUEID() - if err != nil { - return fmt.Errorf("could not extract instance-id (UEID) from instance: %w", err) - } - o.instance = &i - } - - if e.Class == nil { - return fmt.Errorf("class not found in environment") - } - - classID := e.Class.ClassID - if classID == nil { - return fmt.Errorf("class-id not found in class") - } - - if classID.Type() != comid.UUIDType { - return fmt.Errorf("class-id not in UUID format") - } - - o.class = classID.String() - - return nil -} - -func (o *CorimExtractor) SetProfile(profile string) { - o.Profile = profile -} diff --git a/scheme/parsec-tpm/corim_test.go b/scheme/parsec-tpm/corim_test.go new file mode 100644 index 00000000..a8adaf32 --- /dev/null +++ b/scheme/parsec-tpm/corim_test.go @@ -0,0 +1,65 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package parsec_tpm + +import ( + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "ok", + Input: corimParsecTpmValid, + }, + { + Title: "bad instance", + Input: corimParsecTpmBadInstance, + Err: "instance: expected bytes, found uuid", + }, + { + Title: "bad multiple keys", + Input: corimParsecTpmBadMultipleKeys, + Err: "expected exactly one key but got 2", + }, + { + Title: "bad no digest", + Input: corimParsecTpmBadNoDigests, + Err: "measurement 0 does not contain digests", + }, + { + Title: "bad no instance", + Input: corimParsecTpmBadNoInstance, + Err: "instance not set in trust anchor environment", + }, + { + Title: "bad no class", + Input: corimParsecTpmBadNoClass, + Err: "class not set", + }, + { + Title: "bad no class ID", + Input: corimParsecTpmBadNoClassId, + Err: "class ID not set", + }, + { + Title: "bad class ID", + Input: corimParsecTpmBadClassId, + Err: "class ID: expected uuid, found oid", + }, + { + Title: "bad no PCR", + Input: corimParsecTpmBadNoPcr, + Err: "measurement 0 has no key", + }, + { + Title: "bad PCR", + Input: corimParsecTpmBadPcr, + Err: "measurement 0 key: expected uint, found uuid", + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/parsec-tpm/corim_test_vectors.go b/scheme/parsec-tpm/corim_test_vectors.go deleted file mode 100644 index bbd74b20..00000000 --- a/scheme/parsec-tpm/corim_test_vectors.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import _ "embed" - -var ( - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyGood.cbor - unsignedCorimComidParsecTpmKeyGood []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyNoClass.cbor - unsignedCorimComidParsecTpmKeyNoClass []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyNoClassId.cbor - unsignedCorimComidParsecTpmKeyNoClassId []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyNoInstance.cbor - unsignedCorimComidParsecTpmKeyNoInstance []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownClassIdType.cbor - unsignedCorimComidParsecTpmKeyUnknownClassIdType []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownInstanceType.cbor - unsignedCorimComidParsecTpmKeyUnknownInstanceType []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmKeyManyKeys.cbor - unsignedCorimComidParsecTpmKeyManyKeys []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor - unsignedCorimComidParsecTpmPcrsGood []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmPcrsNoClass.cbor - unsignedCorimComidParsecTpmPcrsNoClass []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmPcrsNoPCR.cbor - unsignedCorimComidParsecTpmPcrsNoPCR []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor - unsignedCorimComidParsecTpmPcrsUnknownPCRType []byte - - //go:embed test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor - unsignedCorimComidParsecTpmPcrsNoDigests []byte -) diff --git a/scheme/parsec-tpm/endorsement_handler.go b/scheme/parsec-tpm/endorsement_handler.go deleted file mode 100644 index 4228eb7f..00000000 --- a/scheme/parsec-tpm/endorsement_handler.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2023-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "errors" - - "mime" - - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common" -) - -type EndorsementHandler struct{} - -func (o EndorsementHandler) Init(params handler.EndorsementHandlerParams) error { - return nil // no-op -} - -func (o EndorsementHandler) Close() error { - return nil // no-op -} - -func (o EndorsementHandler) GetName() string { - return "corim (Parsec TPM profile)" -} - -func (o EndorsementHandler) GetAttestationScheme() string { - return SchemeName -} - -func (o EndorsementHandler) GetSupportedMediaTypes() []string { - return EndorsementMediaTypes -} - -func (o EndorsementHandler) Decode(data []byte, mediaType string, caCertPool []byte) (*handler.EndorsementHandlerResponse, error) { - extractor := &CorimExtractor{} - - if mediaType != "" { - mt, _, err := mime.ParseMediaType(mediaType) - if err != nil { - return nil, err - } - - // Use signed decoder for signed CoRIM - if mt == "application/rim+cose" { - return common.SignedCorimDecoder(data, extractor, caCertPool) - } - } - - // Default to unsigned CoRIM decoder - return common.UnsignedCorimDecoder(data, extractor) -} - -func (o EndorsementHandler) CoservRepackage(coservQuery string, resultSet []string) ([]byte, error) { - return nil, errors.New("Parsec TPM CoservRepackage not implemented") -} diff --git a/scheme/parsec-tpm/endorsement_handler_test.go b/scheme/parsec-tpm/endorsement_handler_test.go deleted file mode 100644 index 2ecf95d3..00000000 --- a/scheme/parsec-tpm/endorsement_handler_test.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2023-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDecoder_Decode_OK(t *testing.T) { - tvs := [][]byte{ - unsignedCorimComidParsecTpmKeyGood, - unsignedCorimComidParsecTpmPcrsGood, - } - - d := &EndorsementHandler{} - - for _, tv := range tvs { - _, err := d.Decode(tv, "", nil) - assert.NoError(t, err) - } -} - -func TestDecoder_Decode_negative_tests(t *testing.T) { - tvs := []struct { - desc string - input []byte - expectedErr string - }{ - { - desc: "key without instance identifier", - input: unsignedCorimComidParsecTpmKeyNoInstance, - expectedErr: `bad key in CoMID at index 0: failed to create trust anchor raw public key: instance not found in ID`, - }, - { - desc: "key with an instance identifier of an unexpected type", - input: unsignedCorimComidParsecTpmKeyUnknownInstanceType, - expectedErr: `bad key in CoMID at index 0: could not extract id from AVK environment: could not extract instance-id (UEID) from instance: instance-id type is: *comid.TaggedUUID`, - }, - { - desc: "key without class", - input: unsignedCorimComidParsecTpmKeyNoClass, - expectedErr: `bad key in CoMID at index 0: could not extract id from AVK environment: class not found in environment`, - }, - { - desc: "key without class id", - input: unsignedCorimComidParsecTpmKeyNoClassId, - expectedErr: `bad key in CoMID at index 0: could not extract id from AVK environment: class-id not found in class`, - }, - { - desc: "key class id of an unexpected type", - input: unsignedCorimComidParsecTpmKeyUnknownClassIdType, - expectedErr: `bad key in CoMID at index 0: could not extract id from AVK environment: class-id not in UUID format`, - }, - { - desc: "key with multiple keys", - input: unsignedCorimComidParsecTpmKeyManyKeys, - expectedErr: `bad key in CoMID at index 0: expecting exactly one AK public key`, - }, - { - desc: "measurement without class", - input: unsignedCorimComidParsecTpmPcrsNoClass, - expectedErr: `bad software component in CoMID at index 0: could not extract id from ref-val environment: class not found in environment`, - }, - { - desc: "measurement without the associated PCR", - input: unsignedCorimComidParsecTpmPcrsNoPCR, - expectedErr: `bad software component in CoMID at index 0: could not extract PCR: measurement key is not present`, - }, - { - desc: "measurement with PCR of an unexpected type", - input: unsignedCorimComidParsecTpmPcrsUnknownPCRType, - expectedErr: `bad software component in CoMID at index 0: could not extract PCR: measurement key is not uint: measurement-key type is: *comid.TaggedUUID`, - }, - { - desc: "measurement with PCR without digests", - input: unsignedCorimComidParsecTpmPcrsNoDigests, - expectedErr: `bad software component in CoMID at index 0: measurement[0]: measurement value does not contain digests`, - }, - } - - for _, tv := range tvs { - t.Run(tv.desc, func(t *testing.T) { - d := &EndorsementHandler{} - _, err := d.Decode(tv.input, "", nil) - assert.EqualError(t, err, tv.expectedErr) - }) - } -} - -func TestDecoder_GetAttestationScheme(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetAttestationScheme() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetSupportedMediaTypes(t *testing.T) { - d := &EndorsementHandler{} - - expected := EndorsementMediaTypes - - actual := d.GetSupportedMediaTypes() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_Init(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Init(nil)) -} - -func TestDecoder_Close(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Close()) -} - -func TestDecoder_Decode_empty_data(t *testing.T) { - d := &EndorsementHandler{} - - emptyData := []byte{} - - expectedErr := `empty data` - - _, err := d.Decode(emptyData, "", nil) - - assert.EqualError(t, err, expectedErr) -} - -func TestDecoder_Decode_invalid_data(t *testing.T) { - d := &EndorsementHandler{} - - invalidCbor := []byte("invalid CBOR") - - expectedErr := `CBOR decoding failed` - - _, err := d.Decode(invalidCbor, "", nil) - - assert.ErrorContains(t, err, expectedErr) -} diff --git a/scheme/parsec-tpm/evidence_handler.go b/scheme/parsec-tpm/evidence_handler.go deleted file mode 100644 index c7f04f58..00000000 --- a/scheme/parsec-tpm/evidence_handler.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "bytes" - "crypto" - "encoding/json" - "errors" - "fmt" - "sort" - - "github.com/veraison/ear" - "github.com/veraison/parsec/tpm" - "github.com/veraison/services/handler" - "github.com/veraison/services/log" - "github.com/veraison/services/proto" - "github.com/veraison/services/scheme/common" - "github.com/veraison/swid" -) - -type EvidenceHandler struct{} - -type SwAttr struct { - AlgID *uint64 `json:"parsec-tpm.alg-id"` - ClassID *string `json:"parsec-tpm.class-id"` - Digest *[]byte `json:"parsec-tpm.digest"` - PCR *uint `json:"parsec-tpm.pcr"` -} - -type Endorsements struct { - Scheme string `json:"scheme"` - Type string `json:"type"` - Attr SwAttr `json:"attributes"` -} - -type TaAttr struct { - VerifKey *string `json:"parsec-tpm.ak-pub"` - ClassID *string `json:"parsec-tpm.class-id"` - InstID *string `json:"parsec-tpm.instance-id"` -} - -type TaEndorsements struct { - Scheme string `json:"scheme"` - Type string `json:"type"` - Attr TaAttr `json:"attributes"` -} - -func (s EvidenceHandler) GetName() string { - return "parsec-tpm-evidence-handler" -} - -func (s EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func (s EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - var evidence tpm.Evidence - - err := evidence.FromCBOR(token.Data) - if err != nil { - return nil, handler.BadEvidence(err) - } - - claims, err := evidenceAsMap(evidence) - if err != nil { - return nil, handler.BadEvidence(err) - } - - return claims, nil -} - -func (s EvidenceHandler) ValidateEvidenceIntegrity(token *proto.AttestationToken, trustAnchors []string, endorsements []string) error { - var ( - endorsement TaEndorsements - ev tpm.Evidence - ) - - if err := ev.FromCBOR(token.Data); err != nil { - return handler.BadEvidence(err) - } - - if err := json.Unmarshal([]byte(trustAnchors[0]), &endorsement); err != nil { - log.Errorf("Could not decode trust anchor in ValidateEvidenceIntegrity: %v", err) - return fmt.Errorf("could not decode trust anchor: %w", err) - } - - ta := *endorsement.Attr.VerifKey - pk, err := common.DecodePemSubjectPubKeyInfo([]byte(ta)) - if err != nil { - return fmt.Errorf("could not get public key from trust anchor: %w", err) - } - - if err := ev.Verify(pk); err != nil { - return handler.BadEvidence(err) - } - - log.Debug("Token Signature Verified") - return nil -} - -func (s EvidenceHandler) AppraiseEvidence(ec *proto.EvidenceContext, endorsementStrings []string) (*ear.AttestationResult, error) { - result := handler.CreateAttestationResult(SchemeName) - var endorsements []Endorsements // nolint:prealloc - - for i, e := range endorsementStrings { - var endorsement Endorsements - - if err := json.Unmarshal([]byte(e), &endorsement); err != nil { - return nil, fmt.Errorf("could not decode endorsement at index: %d, %w", i, err) - } - - endorsements = append(endorsements, endorsement) - } - err := populateAttestationResult(result, ec.Evidence.AsMap(), endorsements) - return result, err -} - -func evidenceAsMap(e tpm.Evidence) (map[string]interface{}, error) { - data, err := e.ToJSON() - if err != nil { - return nil, err - } - - var out map[string]interface{} - err = json.Unmarshal(data, &out) - - return out, err -} - -func populateAttestationResult( - result *ear.AttestationResult, - evidence map[string]interface{}, - endorsements []Endorsements, -) error { - appraisal := result.Submods[SchemeName] - - // once the signature on the token is verified, we can claim the HW is - // authentic - appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim - - ev, err := mapAsEvidence(evidence) - if err != nil { - return handler.BadEvidence(err) - } - - attInfo, err := ev.Pat.GetAttestationInfo() - if err != nil { - return handler.BadEvidence(err) - } - - pcrs := attInfo.PCR.PCRinfo.PCRs - hashAlgID := attInfo.PCR.PCRinfo.HashAlgID - pcrDigest := attInfo.PCR.PCRDigest - - // Match the Evidence PCR against the endorsements to generate a subset - // of matching endorsements - eds, err := matchPCRs(pcrs, hashAlgID, endorsements) - if err != nil { - appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim - log.Errorf("match PCR failed: %v", err) - return fmt.Errorf("match PCR failed: %w", err) - } - - if err := matchPCRDigest(pcrDigest, hashAlgID, eds); err != nil { - appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim - log.Errorf("match PCR Digest failed: %v", err) - return fmt.Errorf("match failed for PCR Digest: %w", err) - } - - appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim - appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim - log.Debug("matchPCRs and matchPCRDigest Success") - - // Populate Veraison Key Attestation Extension - key, err := ev.Kat.DecodePubArea() - if err != nil { - return handler.BadEvidence(err) - } - if err := appraisal.SetKeyAttestation(key); err != nil { - return fmt.Errorf("setting extracted public key: %w", err) - } - appraisal.UpdateStatusFromTrustVector() - appraisal.VeraisonAnnotatedEvidence = &evidence - return nil -} - -func mapAsEvidence(in map[string]interface{}) (*tpm.Evidence, error) { - evidence := &tpm.Evidence{} - data, err := json.Marshal(in) - if err != nil { - return nil, err - } - err = evidence.FromJSON(data) - if err != nil { - return nil, fmt.Errorf("unable to map to evidence: %w", err) - } - return evidence, err -} - -// match the evidence PCR's against the received Endorsements -func matchPCRs(pcrs []int, algID uint64, endorsements []Endorsements) ([]Endorsements, error) { - var eds []Endorsements - - if len(pcrs) == 0 { - return nil, errors.New("no evidence pcrs to match") - } - - // Sort the PCRs first - sort.Ints(pcrs) - for i, pcr := range pcrs { - matched := false - for _, end := range endorsements { - if (end.Attr.PCR == nil) || (end.Attr.AlgID == nil) { - log.Errorf("malformed endorsements: %v", end) - continue - } - - if (pcr == int(*end.Attr.PCR)) && (algID == *end.Attr.AlgID) { - eds = append(eds, end) - matched = true - break - } - } - if !matched { - return nil, fmt.Errorf("unmatched pcr value: %d at index: %d", pcr, i) - } - } - return eds, nil -} - -func matchPCRDigest(pDigest []byte, algID uint64, eds []Endorsements) error { - // concatenate endorsement PCR Digests to get the resulting hash data - hdata, err := concatHash(eds) - if err != nil { - return fmt.Errorf("hash concatenation failed: %w", err) - } - // Compute the hash of resulting hash data - endHash, err := computeHash(hdata, algID) - if err != nil { - return fmt.Errorf("unable to compute digest: %w", err) - } - if !bytes.Equal(pDigest, endHash) { - return errors.New("PCR Digest and Endorsement Digest match failed") - } - return nil -} - -func concatHash(endorsements []Endorsements) ([]byte, error) { - var digest []byte - if len(endorsements) == 0 { - return nil, errors.New("no endorsments to hash") - } - - for _, ed := range endorsements { - digest = append(digest, *ed.Attr.Digest...) - } - return digest, nil -} - -// hashFunc returns the hash associated with the algorithms supported -// within tpm library -func hashFunc(alg uint64) crypto.Hash { - switch alg { - case swid.Sha256: - return crypto.SHA256 - case swid.Sha384: - return crypto.SHA384 - case swid.Sha512: - return crypto.SHA512 - default: - return 0 - } -} - -func computeHash(in []byte, algID uint64) ([]byte, error) { - h := hashFunc(algID) - if !h.Available() { - return nil, fmt.Errorf("unavailable hash function for algID: %d", algID) - } - hh := h.New() - if _, err := hh.Write(in); err != nil { - return nil, err - } - return hh.Sum(nil), nil -} diff --git a/scheme/parsec-tpm/evidence_handler_test.go b/scheme/parsec-tpm/evidence_handler_test.go deleted file mode 100644 index 65773d94..00000000 --- a/scheme/parsec-tpm/evidence_handler_test.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "encoding/json" - "errors" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/services/proto" -) - -func Test_ExtractClaims_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - } - ta := string(taEndValBytes) - claims, err := handler.ExtractClaims(&token, []string{ta}) - require.NoError(t, err) - assert.Equal(t, claims["kat"].(map[string]interface{})["kid"].(string), claims["pat"].(map[string]interface{})["kid"].(string)) -} - -func Test_ExtractClaims_nok_bad_evidence(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/bad_evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - expectedErr := "CBOR decoding of Parsec TPM attestation failed cbor: invalid additional information 28 for type byte string" - h := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - } - ta := string(taEndValBytes) - _, err = h.ExtractClaims(&token, []string{ta}) - err1 := errors.Unwrap(err) - require.NotNil(t, err1) - assert.EqualError(t, err1, expectedErr) -} - -func Test_GetRefValueIDs_nok_bad_endorsement(t *testing.T) { - taEndValBytes, err := os.ReadFile("test/evidence/bad_ta_endorsements.json") - require.NoError(t, err) - expectedErr := "could not decode endorsement: json: cannot unmarshal number into Go struct field TaAttr.attributes.parsec-tpm.class-id of type string" - - h := &StoreHandler{} - - ta := string(taEndValBytes) - claims := map[string]interface{}{} - - _, err = h.GetRefValueIDs("0", []string{ta}, claims) - assert.EqualError(t, err, expectedErr) -} - -func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - h := &EvidenceHandler{} - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - ta := string(taEndValBytes) - err = h.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - require.NoError(t, err) -} - -func Test_ValidateEvidenceIntegrity_nok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence1.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - expectedErr := "failed to verify signature on key attestation token: failed to verify signature: Verification failed" - h := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - ta := string(taEndValBytes) - err = h.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - err1 := errors.Unwrap(err) - require.NotNil(t, err1) - assert.EqualError(t, err1, expectedErr) -} - -func Test_ValidateEvidenceIntegrity_BadKey(t *testing.T) { - tvs := []struct { - desc string - input string - expectedErr string - }{ - { - desc: "invalid public key", - input: "test/evidence/bad_key_endorsements.json", - expectedErr: `could not get public key from trust anchor: unable to parse public key: asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:1 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} AlgorithmIdentifier @2`, - }, - { - desc: "bad pem key header", - input: "test/evidence/bad_key_header_endorsements.json", - expectedErr: `could not get public key from trust anchor: could not extract trust anchor PEM block`, - }, - { - desc: "incorrect key type", - input: "test/evidence/bad_key_private_key.json", - expectedErr: "could not get public key from trust anchor: unsupported key type: \"PRIVATE KEY\"", - }, - } - - for _, tv := range tvs { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile(tv.input) - require.NoError(t, err) - h := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - ta := string(taEndValBytes) - err = h.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - assert.EqualError(t, err, tv.expectedErr) - } -} -func Test_AppraiseEvidence_nok(t *testing.T) { - tvs := []struct { - desc string - input string - expectedErr string - }{ - { - desc: "no matching pcr values in endorsements", - input: "test/evidence/unmatch_pcr_endorsements.json", - expectedErr: `match PCR failed: unmatched pcr value: 1 at index: 0`, - }, - { - desc: "umatched PCR Digest Information", - input: "test/evidence/unmatch_pcr_digest_endorsements.json", - expectedErr: `match failed for PCR Digest: PCR Digest and Endorsement Digest match failed`, - }, - } - - for _, tv := range tvs { - var endorsemementsArray []string - extractedBytes, err := os.ReadFile("test/evidence/extracted.json") - require.NoError(t, err) - - var ec proto.EvidenceContext - err = json.Unmarshal(extractedBytes, &ec) - require.NoError(t, err) - - endorsementsBytes, err := os.ReadFile(tv.input) - require.NoError(t, err) - - err = json.Unmarshal(endorsementsBytes, &endorsemementsArray) - require.NoError(t, err) - - handler := &EvidenceHandler{} - - _, err = handler.AppraiseEvidence(&ec, endorsemementsArray) - assert.EqualError(t, err, tv.expectedErr) - } -} - -func Test_AppraiseEvidence_ok(t *testing.T) { - var endorsemementsArray []string - extractedBytes, err := os.ReadFile("test/evidence/matched_extracted.json") - require.NoError(t, err) - - var ec proto.EvidenceContext - err = json.Unmarshal(extractedBytes, &ec) - require.NoError(t, err) - endorsementsBytes, err := os.ReadFile("test/evidence/match_pcr_digest_endorsements.json") - require.NoError(t, err) - err = json.Unmarshal(endorsementsBytes, &endorsemementsArray) - require.NoError(t, err) - - handler := &EvidenceHandler{} - - _, err = handler.AppraiseEvidence(&ec, endorsemementsArray) - require.NoError(t, err) -} - -func Test_GetName_ok(t *testing.T) { - scheme := &EvidenceHandler{} - expectedName := "parsec-tpm-evidence-handler" - name := scheme.GetName() - assert.Equal(t, name, expectedName) -} - -func Test_GetAttestationScheme_ok(t *testing.T) { - scheme := &EvidenceHandler{} - expectedScheme := "PARSEC_TPM" - name := scheme.GetAttestationScheme() - assert.Equal(t, name, expectedScheme) -} - -func Test_GetSupportedMediaTypes_ok(t *testing.T) { - expectedMt := "application/vnd.parallaxsecond.key-attestation.tpm" - scheme := &EvidenceHandler{} - mtList := scheme.GetSupportedMediaTypes() - assert.Len(t, mtList, 1) - assert.Equal(t, mtList[0], expectedMt) -} diff --git a/scheme/parsec-tpm/plugin/Makefile b/scheme/parsec-tpm/plugin/Makefile index fc79bb8d..0ebcdf46 100644 --- a/scheme/parsec-tpm/plugin/Makefile +++ b/scheme/parsec-tpm/plugin/Makefile @@ -1,13 +1,11 @@ -# Copyright 2024 Contributors to the Veraison project. +# Copyright 2024-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += endorsement-handler - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-parsec-tpm.plugin +GOPKG := github.com/veraison/services/scheme/parsec-tpm +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk \ No newline at end of file +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/parsec-tpm/plugin/combined/Makefile b/scheme/parsec-tpm/plugin/combined/Makefile deleted file mode 100644 index f5f82797..00000000 --- a/scheme/parsec-tpm/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-tpm.plugin -GOPKG := github.com/veraison/services/scheme/parsec-tpm -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-tpm/plugin/combined/main.go b/scheme/parsec-tpm/plugin/combined/main.go deleted file mode 100644 index 7c44e4f1..00000000 --- a/scheme/parsec-tpm/plugin/combined/main.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2023-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/parsec-tpm" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/parsec-tpm/plugin/endorsement-handler/Makefile b/scheme/parsec-tpm/plugin/endorsement-handler/Makefile deleted file mode 100644 index 0a7aad88..00000000 --- a/scheme/parsec-tpm/plugin/endorsement-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-tpm-endorsement-handler.plugin -GOPKG := github.com/veraison/services/scheme/parsec-tpm -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-tpm/plugin/evidence-handler/Makefile b/scheme/parsec-tpm/plugin/evidence-handler/Makefile deleted file mode 100644 index f937f0ee..00000000 --- a/scheme/parsec-tpm/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2023 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-tpm-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/parsec-tpm -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-tpm/plugin/evidence-handler/main.go b/scheme/parsec-tpm/plugin/evidence-handler/main.go deleted file mode 100644 index df7957e5..00000000 --- a/scheme/parsec-tpm/plugin/evidence-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/parsec-tpm" -) - -func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - plugin.Serve() -} diff --git a/scheme/parsec-tpm/plugin/endorsement-handler/main.go b/scheme/parsec-tpm/plugin/main.go similarity index 61% rename from scheme/parsec-tpm/plugin/endorsement-handler/main.go rename to scheme/parsec-tpm/plugin/main.go index e74655e5..36f47277 100644 --- a/scheme/parsec-tpm/plugin/endorsement-handler/main.go +++ b/scheme/parsec-tpm/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2024-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) plugin.Serve() } diff --git a/scheme/parsec-tpm/plugin/store-handler/Makefile b/scheme/parsec-tpm/plugin/store-handler/Makefile deleted file mode 100644 index cb8b47c8..00000000 --- a/scheme/parsec-tpm/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/parsec-tpm-store-handler.plugin -GOPKG := github.com/veraison/services/scheme/parsec-tpm -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/parsec-tpm/plugin/store-handler/main.go b/scheme/parsec-tpm/plugin/store-handler/main.go deleted file mode 100644 index 8d6ffeb2..00000000 --- a/scheme/parsec-tpm/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/parsec-tpm" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/parsec-tpm/scheme.go b/scheme/parsec-tpm/scheme.go index 84999acd..8c100f0f 100644 --- a/scheme/parsec-tpm/scheme.go +++ b/scheme/parsec-tpm/scheme.go @@ -1,19 +1,293 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2024-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package parsec_tpm -const ( - SchemeName = "PARSEC_TPM" - EndorsementProfile = `"tag:github.com/parallaxsecond,2023-03-03:tpm"` +import ( + "bytes" + "crypto" + "encoding/json" + "errors" + "fmt" + "sort" + + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/parsec/tpm" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + "github.com/veraison/services/scheme/common" + "github.com/veraison/services/vts/appraisal" + "github.com/veraison/swid" + "go.uber.org/zap" ) -var EndorsementMediaTypes = []string{ - // Unsigned CoRIM profiles - `application/corim-unsigned+cbor; profile=` + EndorsementProfile, - // Signed CoRIM profiles - `application/rim+cose; profile=` + EndorsementProfile, +var Descriptor = handler.SchemeDescriptor{ + Name: "PARSEC_TPM", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + }, + EvidenceMediaTypes: []string{ + "application/vnd.parallaxsecond.key-attestation.tpm", + }, +} + +type Implementation struct { + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), + } +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + var parsecEvidence tpm.Evidence + err := parsecEvidence.FromCBOR(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + kat := parsecEvidence.Kat + if kat == nil { + return nil, errors.New("no key attestation token to fetch Key ID") + } + + instanceID, err := comid.NewBytesInstance(*kat.KID) + if err != nil { + return nil, err + } + + return []*comid.Environment{ + { + Instance: instanceID, + }, + }, nil +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + numTAs := len(trustAnchors) + if numTAs != 1 { + return nil, fmt.Errorf("expected exactly one trust anchor, got %d", numTAs) + } + + return []*comid.Environment{ + { + Class: trustAnchors[0].Environment.Class, + }, + }, nil +} + +func (o *Implementation) ValidateComid(c *comid.Comid) error { + return nil +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + var parsecEvidence tpm.Evidence + + err := parsecEvidence.FromCBOR(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + claims, err := common.ToMapViaJSON(parsecEvidence) + if err != nil { + return nil, handler.BadEvidence(err) + } + + return claims, nil +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + var ev tpm.Evidence + + if err := ev.FromCBOR(evidence.Data); err != nil { + return handler.BadEvidence(err) + } + + numKeys := len(trustAnchors[0].VerifKeys) + if numKeys != 1 { + return fmt.Errorf("expected exactly one key in trust anchor, found %d", numKeys) + } + + pk, err := trustAnchors[0].VerifKeys[0].PublicKey() + if err != nil { + return fmt.Errorf("could not get public key from trust anchor: %w", err) + } + + if err := ev.Verify(pk); err != nil { + return handler.BadEvidence(err) + } + + o.logger.Debug("Token Signature Verified") + return nil +} + +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + appraisal := result.Submods[Descriptor.Name] + + // once the signature on the token is verified, we can claim the HW is + // authentic + appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim + + parsecEvidence, err := convertMapToTPMEvidence(claims) + if err != nil { + return result, handler.BadEvidence(err) + } + + attInfo, err := parsecEvidence.Pat.GetAttestationInfo() + if err != nil { + return result, handler.BadEvidence(err) + } + + pcrs := attInfo.PCR.PCRinfo.PCRs + hashAlgID := attInfo.PCR.PCRinfo.HashAlgID + pcrDigest := attInfo.PCR.PCRDigest + + sort.Ints(pcrs) + + matched := false + for i, end := range endorsements { + o.logger.Debugf("attempting to match endorsement %d...", i) + endorsedDigest, ok := computeEndorsedHash(o.logger, pcrs, hashAlgID, end.Measurements.Values) + if !ok { + continue + } + + if bytes.Equal(pcrDigest, endorsedDigest) { + matched = true + break + } else { + o.logger.Debug("failed to match digest") + } + } + + if !matched { + appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim + return result, handler.BadEvidence("failed to match PCRs") + } + + o.logger.Debug("PCR digests matched") + appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim + appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim + + // Populate Veraison Key Attestation Extension + key, err := parsecEvidence.Kat.DecodePubArea() + if err != nil { + return result, handler.BadEvidence(err) + } + + if err := appraisal.SetKeyAttestation(key); err != nil { + return result, fmt.Errorf("setting extracted public key: %w", err) + } + + appraisal.UpdateStatusFromTrustVector() + appraisal.VeraisonAnnotatedEvidence = &claims + + return result, nil +} + +func convertMapToTPMEvidence(in map[string]any) (*tpm.Evidence, error) { + evidence := &tpm.Evidence{} + data, err := json.Marshal(in) + if err != nil { + return nil, err + } + err = evidence.FromJSON(data) + if err != nil { + return nil, fmt.Errorf("unable to map to evidence: %w", err) + } + return evidence, err +} + +func computeEndorsedHash( + logger *zap.SugaredLogger, + pcrs []int, + hashAlgID uint64, + measurements []comid.Measurement, +) ([]byte, bool) { + digests := make(map[int][]byte) + for i, mea := range measurements { + endPcr, err := mea.Key.GetKeyUint() + if err != nil { + logger.Errorf("measurement key at index %d: %w", i, err) + continue + } + + if mea.Val.Digests == nil { + logger.Errorf("no digests in measurement at index %d", i) + continue + } + + for _, digest := range *mea.Val.Digests { + if digest.HashAlgID == hashAlgID { + digests[int(endPcr)] = digest.HashValue + break + } + } + } + + var concatHashes []byte + for _, pcr := range pcrs { + pcrHash, ok := digests[pcr] + if !ok { + logger.Debugf("failed to match PCR %d", pcr) + return nil, false + } + + concatHashes = append(concatHashes, pcrHash...) + } + + hash, err := computeHash(concatHashes, hashAlgID) + if err != nil { + logger.Errorf("unable to compute digest: %w", err) + return nil, false + } + + return hash, true +} + +func computeHash(in []byte, algID uint64) ([]byte, error) { + h := hashFunc(algID) + if !h.Available() { + return nil, fmt.Errorf("unavailable hash function for algID: %d", algID) + } + hh := h.New() + if _, err := hh.Write(in); err != nil { + return nil, err + } + return hh.Sum(nil), nil } -var EvidenceMediaTypes = []string{ - "application/vnd.parallaxsecond.key-attestation.tpm", +// hashFunc returns the hash associated with the algorithms supported +// within tpm library +func hashFunc(alg uint64) crypto.Hash { + switch alg { + case swid.Sha256: + return crypto.SHA256 + case swid.Sha384: + return crypto.SHA384 + case swid.Sha512: + return crypto.SHA512 + default: + return 0 + } } diff --git a/scheme/parsec-tpm/store_handler.go b/scheme/parsec-tpm/store_handler.go deleted file mode 100644 index 25250f73..00000000 --- a/scheme/parsec-tpm/store_handler.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2024-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "net/url" - "strings" - - "github.com/veraison/parsec/tpm" - "github.com/veraison/services/handler" - "github.com/veraison/services/log" - "github.com/veraison/services/proto" -) - -type StoreHandler struct{} - -func (s StoreHandler) GetName() string { - return "parsec-tpm-store-handler" -} - -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -func (s StoreHandler) SynthKeysFromRefValue(tenantID string, refVals *handler.Endorsement) ([]string, error) { - return synthKeysFromAttr(ScopeRefValues, tenantID, refVals.Attributes) -} - -func (s StoreHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) { - return synthKeysFromAttr(ScopeTrustAnchor, tenantID, ta.Attributes) -} - -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - var ev tpm.Evidence - err := ev.FromCBOR(token.Data) - if err != nil { - return []string{""}, handler.BadEvidence(err) - } - - kat := ev.Kat - if kat == nil { - return []string{""}, errors.New("no key attestation token to fetch Key ID") - } - kid := *kat.KID - instance_id := base64.StdEncoding.EncodeToString(kid) - return []string{tpmLookupKey(ScopeTrustAnchor, token.TenantId, "", instance_id)}, nil - -} - -func (s StoreHandler) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - var endorsement TaEndorsements - - if err := json.Unmarshal([]byte(trustAnchors[0]), &endorsement); err != nil { - log.Errorf("Could not decode Endorsements in ExtractClaims: %v", err) - return nil, fmt.Errorf("could not decode endorsement: %w", err) - } - - class_id := *endorsement.Attr.ClassID - return []string{tpmLookupKey(ScopeRefValues, tenantID, class_id, "")}, nil -} - -func synthKeysFromAttr(scope, tenantID string, attr json.RawMessage) ([]string, error) { - var ( - instance string - class string - err error - ) - - switch scope { - case ScopeTrustAnchor: - var ta TaAttr - if err := json.Unmarshal(attr, &ta); err != nil { - return nil, fmt.Errorf("unable to extract endorsements from TA: %w", err) - } - if ta.ClassID == nil || ta.InstID == nil { - return nil, fmt.Errorf("missing InstID or ClassID from TA: %w", err) - } - class = *ta.ClassID - instance = *ta.InstID - case ScopeRefValues: - var sw SwAttr - if err := json.Unmarshal(attr, &sw); err != nil { - return nil, fmt.Errorf("unable to extract endorsements from RefVal: %w", err) - } - if sw.ClassID == nil { - return nil, fmt.Errorf("missing ClassID in reference value: %w", err) - } - class = *sw.ClassID - default: - return nil, fmt.Errorf("invalid scope argument: %s", scope) - } - - return []string{tpmLookupKey(scope, tenantID, class, instance)}, nil -} - -func tpmLookupKey(scope, tenantID, class, instance string) string { - var absPath []string - - switch scope { - case ScopeTrustAnchor: - absPath = []string{instance} - case ScopeRefValues: - absPath = []string{class} - } - - u := url.URL{ - Scheme: SchemeName, - Host: tenantID, - Path: strings.Join(absPath, "/"), - } - - return u.String() -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - return []string{"TODO"}, nil -} diff --git a/scheme/parsec-tpm/store_handler_test.go b/scheme/parsec-tpm/store_handler_test.go deleted file mode 100644 index 142f0743..00000000 --- a/scheme/parsec-tpm/store_handler_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package parsec_tpm - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -func Test_GetTrustAnchorIDs_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/evidence/evidence.cbor") - require.NoError(t, err) - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - } - - expectedTaID := "PARSEC_TPM://1/AYiFVFnuuemzSkbrSMs58vaqadoEUioybRI9XFAfziEM" - - handler := &StoreHandler{} - - taIDs, err := handler.GetTrustAnchorIDs(&token) - require.NoError(t, err) - assert.Equal(t, []string{expectedTaID}, taIDs) -} - -func Test_GetRefValueIDs_ok(t *testing.T) { - rawTA, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - - trustAnchors := []string{string(rawTA)} - - rawToken, err := os.ReadFile("test/evidence/extracted.json") - require.NoError(t, err) - - tokenJSON := make(map[string]interface{}) - err = json.Unmarshal(rawToken, &tokenJSON) - require.NoError(t, err) - - claims := tokenJSON["evidence"].(map[string]interface{}) - - expectedRefvalID := "PARSEC_TPM://1/cd1f0e55-26f9-460d-b9d8-f7fde171787c" - - handler := &StoreHandler{} - - refvalIDs, err := handler.GetRefValueIDs("1", trustAnchors, claims) - require.NoError(t, err) - assert.Equal(t, []string{expectedRefvalID}, refvalIDs) -} - - -func Test_SynthKeysFromTrustAnchor_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/evidence/ta_endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "PARSEC_TPM://1/AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromTrustAnchor("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) - -} - -func Test_SynthKeysFromRefValue_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/evidence/refval-endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "PARSEC_TPM://1/cd1f0e55-26f9-460d-b9d8-f7fde171787c" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromRefValue("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) -} diff --git a/scheme/parsec-tpm/test/corim/build-test-vectors.sh b/scheme/parsec-tpm/test/corim/build-test-vectors.sh deleted file mode 100755 index d79fd548..00000000 --- a/scheme/parsec-tpm/test/corim/build-test-vectors.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -set -eu -set -o pipefail - -THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -GEN_CORIM="$THIS_DIR/../../../common/scripts/gen-corim" - -CORIM_TEMPLATE=corimMini - -COMID_TEMPLATES=( - ComidParsecTpmKeyGood - ComidParsecTpmKeyNoClass - ComidParsecTpmKeyNoClassId - ComidParsecTpmKeyNoInstance - ComidParsecTpmKeyUnknownClassIdType - ComidParsecTpmKeyUnknownInstanceType - ComidParsecTpmKeyManyKeys - ComidParsecTpmPcrsGood - ComidParsecTpmPcrsNoClass - ComidParsecTpmPcrsNoPCR - ComidParsecTpmPcrsUnknownPCRType - ComidParsecTpmPcrsNoDigests -) - -for comid in "${COMID_TEMPLATES[@]}" -do - "$GEN_CORIM" "$THIS_DIR" "$comid" "$CORIM_TEMPLATE" "unsigned" -done - -echo "done" diff --git a/scheme/parsec-tpm/test/corim/compile-endorsements.sh b/scheme/parsec-tpm/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..8bac52e5 --- /dev/null +++ b/scheme/parsec-tpm/test/corim/compile-endorsements.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p parsec_tpm "$THIS_DIR"/corim-*.cbor + diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownClassIdType.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-class-id.cbor similarity index 83% rename from scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownClassIdType.cbor rename to scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-class-id.cbor index e8554b7095997894da57ef83b3595d57bd643bfb..f3b74640d5f56ce374bd4d999fb158be97aa67f9 100644 GIT binary patch delta 53 ncmZo+p2e(llkw|fh6+^!D9{Db5W>vd%mU1U$r)`F%VPupbQ}zq delta 31 ncmbQm+`=q&lkw|fhJej)*!Z-fy$|&l%C6=(7yWXhP97rw!8QzV diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownInstanceType.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-instance.cbor similarity index 82% rename from scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownInstanceType.cbor rename to scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-instance.cbor index 581bca43dd1e7e6f2b197488ae0a67303a6aece1..6d3430b301c8d327bd6dbe746a59a4fbda114722 100644 GIT binary patch delta 53 ncmeyzG=*8`Cgaz|3>B&dP@oHa{dmrjAlwHknF8bw0oeV|*&L#}q diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyManyKeys.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-multiple-keys.cbor similarity index 77% rename from scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyManyKeys.cbor rename to scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-multiple-keys.cbor index cdc57c4660d76e0f7a3ca12a6b2097a3e0de13d4..19af7d170529b424269260dbca03a6a18dfca788 100644 GIT binary patch delta 67 zcmX@ca)(9dCgaz|3>B&dP@oHWcup~yIKqV&WCtQ*(NVgvwZ CVGpS=MWn-2~E diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoClassId.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-class-id.cbor similarity index 83% rename from scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoClassId.cbor rename to scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-class-id.cbor index 3f2d87418660b662d8030ee94b234e987ad31dc3..2efbc8d3898afd1da656abf09ed856e1aebbf451 100644 GIT binary patch delta 53 ncmeBRp2w_nlkw|fh6+^!D9{Db5W>vd%mU1U$(e2xD`Eryb<+%{ delta 31 ncmbQo+`%k%lkw|fhJej)*!Z-fy$|&l%C6=(7yWXhP7xyj!Y&Ma diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoClass.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-class.cbor similarity index 82% rename from scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoClass.cbor rename to scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-class.cbor index 331f83f2e20a76575683db2e6b08a9cbfd4e1885..f5e9c2f1f37f61db47a89813467d970f26f69870 100644 GIT binary patch delta 53 ncmey(G?7{7Cgaz|3>B&dP@oHa{dmrjAlwHknF8bw0om55u&1?+R diff --git a/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-digests.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-digests.cbor new file mode 100644 index 0000000000000000000000000000000000000000..9bec82c999e04f1ba3fabed768e885e5bf75e161 GIT binary patch literal 213 zcmcb~_;oQug{lD*=z?enVPvd%mU1U$ysa^3t{kWWc zH~WGqQ{!TWw1C8-;?!iu8wwSQ86_nJ#a86s-NrAd0p`MLT9iA9MyIf)fOCHZ+N zOwA08Oe_l-8k-g}EM&N$8gN#gFI4TP8}H5=-~T==tf*;P$heTHsfjT{q1~zfs8WNi zAzNJaIhzmmPf9t{44*!z-dn|gFX6~})#FX<5e7~zTQhx@9k_Jfy>r3Ns1r;vjlEBm zSO|vIJxQISGeKpR+#VTGveBFrR;0-%%H0emkAws zvPkvxB-Tp|h0hL`yMhc?WZ(Tf@y}A-slr*pA-Ai1uU1Q|?c=pwE<10NW!q-&WumLU o1^RrBi<-AIidmPftAe>grzA1m3a8(7j0}v7bqzqss-z$n0Al%_Q2+n{ literal 0 HcmV?d00001 diff --git a/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-pcr.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-pcr.cbor new file mode 100644 index 0000000000000000000000000000000000000000..d4a002b5805ae0e304f3045d51fc431bae4305ac GIT binary patch literal 429 zcmcb~_;oQug{lD*=z?enVPjo-b7GryK9i8{hvvEUc($S_Bd`$ml9i`r(<@7u5Z{ z@=o|J#)V8xO^gu=?N0qil^Sdf+2X3t*?h2nQp%ZT`1C>b-YWik2}jPW9&cigFmP(w zn(4Fbz@_ulklGX9EWY+cN_kRf0u<0O^vRW5t>{kWWc zH~WGqQ{!TWw1C8-;?!iu8wwSQ86_nJ#a86s-NrAd0p`MLT9iA9MyIf)fOCHZ+N zOwA08Oe_l-8k-g}EM&N$8gN#gFI4TP8}H5=-~T==tf*;T#K6F~kg2JOF+zcX0BB;5 zFmP(wn(4Fbz@_uE?ZXxI4WGhQSt6U{^XZUzI&#&CUG_9=tYtn70iuIi?Bxp<4q=m2t~$@){w|| zJ6~@0a(nG@+Va!4RhhR~g0zfsg=}L2d|J`ohx!X;S96?;e#zK)lkrz1qswB(g$x1j9^_Ac+2p%tYHJc# zV~$=VQ{!TWw1C8-;?!iu8wwSQ86_nJ#a86s-NrAd0p`MLT9iA9MyIf)fOCHZ+N zOwA08Oe_nT8=Dp}EM&N$8gN#gFI4TP8}H5=-~T==tf*nU$)pyc$jCqdG~Q&=s@R|l z0#2^(o_-1ep-w)Y&I;bHkzheCU$^XX*YZdY@BApwsw@L%$G}KWDBHy`Fxe$A-O)9~ zJIKvdKd3x7B0t~L!X+iKB)~s1UB5KbJJ%?ps3b(c)YaFutS~UDsNBoLBRQ?yAlW!P ztjayV(8oAZKhUfq+rup_B{Zxs*eE;zXo7j#!KSLl=^rd#0* S9UUVBBV%0y5V9&M$OQncfqypu diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor deleted file mode 100644 index 88caca635e711f245122373bdb9ee9b0f8300802..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 371 zcmcb~_;oQuz~(n>d|J`ohx!X;S96?;e#zK)lkrz1quOG|g$w~R87HZPuX5S5@5klr zyV(~^nHm=}qy;1v6{jXM-cYDe%qS@-D7MnqPtPpLC{5B!&d=2^NGwXs$w{mLD#_1F zVQOYzWMWy!(Acz)VIji})qu0|e4%PT-FSE2`2P1{VMR^TA_fM=g-lINj1da$PW?xf z8f*>O;;PTte6W8~%9&>P^g;FBD*k&3N6xDrZ(@%yaBA6_>9g#>rStBc3wB1GV2Ww% zeX7i2=KcJvX5*$yZ;!QZR#LA!6d^fHMfk?aO$Wa&Vqkd|J`ohx!X;S96?;e#zK)lkrz1qxoXSg$w~R87HZPuX5S5@5klr zyV(~^nHm=}qy;1v6{jXM-cYDe%qS@-D7MnqPtPpLC{5B!&d=2^NGwXs$w{mLD#_1F zVQOYzWMWy!(Acz)@g|d6gd!sY0noIFfq`)$Q&SUTghIPh|52p|TSKT@<9?4Oi! zrWrncP`$T`|6an8^Qy<2*dq*_TDE5TEIV-NynE+@olz&4Vj6p&Dzlh*KR>J4xarc{ zW38K&)awpKNKR7`zHxHX!LN%L7-7b*TVcMV&xmW!m9nqRGlQ-^Tqbnj$s*O$lUOe? z6h1p#?g}zqk$v~`#6L@QrwV5Yhup66y;?1;wvX3#x$L}6mTjB8mx-?a7U=UiE^6M= gC}v%@t_tP~osz_KE1UtMV`N}ttZM*5RwV_w07q_=Jpcdz diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor deleted file mode 100644 index bd2346c9b963bccbf6a31c898f5d7e4c942233d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191 zcmcb~_;oQuz~(n>d|J`ohx!X;S96?;e#zK)lkrzX@nXh>3;{D4C#i(5a@n)*$K~w1 z*%wTi8W%I91tb;~rzSJrP^eJMC@Co@w$j&6&n(F(P0~xw&($wTEK1DDNvr@W$d|J`ohx!X;S96?;e#zK)lkrz1qtar=g$w~R87HZPuX5S5@5klr zyV(~^nHm=}qy;1v6{jXM-cYDe%qS@-D7MnqPtPpLC{5B!&d=2^NGwXs$w{mLD#_1F zVQOYzWMWy!(Acz)VIji})qu0|e4%PT-FSE2`2P1{VMR^TLdJzmO-+mu3hhq)N0l0E z4cX$V&)Iyie^SbsX880$_1-G}dkII*s~&G+k1%j**_!FI?7*e-?wt#EMx9`aY3zNf z%wp#K{H$iq_wzrqb)x59i!pApxdD`j7sX9it;xJ>B4 zlSQhhC$U~)D13If+!bWFBKz*=iGP;rP8H4)4!K?Bd$n3xZ6B}ga@l#CEZa7FFB4t; oEzsw4T-3a!QOvq*T@}m~IwgteRyh5xV`N}ttZM*5RwV_w0FiE;BLDyZ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor deleted file mode 100644 index 95bbfd9cf070ad819c969f9dd6d8882c383f0b33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 407 zcmcb~_;oQuz~(n>d|J`ohx!X;S96?;e#zK)lkrz1qt{}_g$w~R87HZPuX5S5@5klr zyV(~^nHm=}qy;1v6{jXM-cYDe%qS@-D7MnqPtPpLC{5B!&d=2^NGwXs$w{mLD#_1F zVQOYzWMWy!(Acz)VIji})qu0|e4%PT-FSE2`2P1{VMR^TB9N#-MpuE-56`r|pzi0D zcfxluE@WzIVvJB|cj`Z?)L?7K7FT`F=7ar{QqDBPrw^+4R`K6UIC5U~coTbsfm6%Y zOrK>3E}eJpT(C3h1XE07?^9(KGwceG12c9faJw1u_5<}s$!{x3Z z3l-USKTrI#RClUymT<`JD&MQs(rWv7ZI{c=+hp0c*?XDj>TiKQpW~wDEsbKdan1ti{$Lg zln6z}6&ylGc@m5Z%cClT9x!nEcuIbX|F&Hu{g;tT;Nb$E^z?$#B*&uE#E1w6WuV0@ z3`GnK3<6+BFav3Y>qgJxbeRfRba>j87ac7YW##*y+}qjdb+<%q-??knbqoqlw_0^o z_wANgdW?5wNQ3O2Q;rgLTT=vsEi-HUj;~zIn30@XRN|SJmLDrBJlBJ+12um$WHo_7QXL+x^z43YR zv%j^|&(~Mpytq8bBfybMEUZ#x&V`(fhL;!=1iuFGmd$&#L2u>ii8C%HH?TYKTspk( Y /dev/null && pwd ) +SRC_DIR="$THIS_DIR/src" + +diag2cbor.rb < "$SRC_DIR/evidence.diag" > "$THIS_DIR/evidence.cbor" diff --git a/scheme/parsec-tpm/test/evidence/evidence1.cbor b/scheme/parsec-tpm/test/evidence/evidence1.cbor deleted file mode 100644 index 7c03a9e3a7fd2253906fa178d350fe047d9d8dce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 661 zcmZ3KoSj&*EUlyDPU%#;X4#uXewM|l#A3(KP_gB~z&`FKixivPAk6>OW@%Gp7ivB(j>>C)WnDg z24$edEDS{q3=9HbM=%3vh3iJo<8+w{Saf*Wl@}c?7G>r8pWNHo>2Ptzc3V>fgDo>_{En|&%$Sj!T2$hhmzEzf@qdW3dxJQG z5(9VX!jST7cV_0TJnY9&`oZe(M%xIb=G)VlN`po7Ret+*F|Zf_0njN7IgF2Ed{>sA zzZk{+mvL|VwB_qH+dhDd$olFXb!vr6w%**SFL+*CEbi3bP`G8SjM=rds&{YwzRL?z z!x+n!64CphWq$U-W%^=bTd#9VZw#%Ez9X5pwmW1^>5=4u#FC}>;^8dswYN7uFMjs7 zcKZ4H%9|IL2YCcIa*2gis?52Nv(fMpgM#4K0N%2Bk9M4&+$4Oa@59n{OD5zjUi4k- znwH~^o9-OTh>VA<#FCQKVn{fZg2PFI /dev/null && pwd ) + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession?nonce=byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA== 2>/dev/null | grep "location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H "content-type: $EVIDENCE_CONTENT_TYPE" --data-binary @"$THIS_DIR/$EVIDENCE_FILE" https://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/parsec-tpm/test/evidence/ta_endorsements.json b/scheme/parsec-tpm/test/evidence/ta_endorsements.json deleted file mode 100644 index 61f066db..00000000 --- a/scheme/parsec-tpm/test/evidence/ta_endorsements.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scheme": "PARSEC_TPM", - "type": "VERIFICATION_KEY", - "attributes": { - "parsec-tpm.ak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2lB1xtcIWePIt/Wwt+s8Ybp+5ji8\nt2pzGDKSOG7xTGK5gOYkcLCHz4i4L/yGzyEmBO1mZFZNuJz14X0J24+XQQ==\n-----END PUBLIC KEY-----", - "parsec-tpm.class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c", - "parsec-tpm.instance-id": "AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn" - } -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/unmatch_pcr_digest_endorsements.json b/scheme/parsec-tpm/test/evidence/unmatch_pcr_digest_endorsements.json deleted file mode 100644 index cde3380d..00000000 --- a/scheme/parsec-tpm/test/evidence/unmatch_pcr_digest_endorsements.json +++ /dev/null @@ -1,4 +0,0 @@ -["{\"scheme\":\"PARSEC_TPM\",\"type\":\"REFERENCE_VALUE\",\"attributes\":{\"parsec-tpm.alg-id\":1,\"parsec-tpm.class-id\":\"YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"parsec-tpm.digest\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"parsec-tpm.pcr\":1}}", - "{\"scheme\":\"PARSEC_TPM\",\"type\":\"REFERENCE_VALUE\",\"attributes\":{\"parsec-tpm.alg-id\":1,\"parsec-tpm.class-id\":\"YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"parsec-tpm.digest\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"parsec-tpm.pcr\":2}}", - "{\"scheme\":\"PARSEC_TPM\",\"type\":\"REFERENCE_VALUE\",\"attributes\":{\"parsec-tpm.alg-id\":1,\"parsec-tpm.class-id\":\"YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"parsec-tpm.digest\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"parsec-tpm.pcr\":3}}" -] \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/unmatch_pcr_endorsements.json b/scheme/parsec-tpm/test/evidence/unmatch_pcr_endorsements.json deleted file mode 100644 index 0c47d054..00000000 --- a/scheme/parsec-tpm/test/evidence/unmatch_pcr_endorsements.json +++ /dev/null @@ -1,3 +0,0 @@ -[ - "{\"scheme\":\"PARSEC_TPM\",\"type\":\"REFERENCE_VALUE\",\"attributes\":{\"parsec-tpm.alg-id\":1,\"parsec-tpm.class-id\":\"YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\"parsec-tpm.digest\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\",\"parsec-tpm.pcr\":0}}" -] \ No newline at end of file diff --git a/scheme/parsec-tpm/test_vars.go b/scheme/parsec-tpm/test_vars.go new file mode 100644 index 00000000..bc7b2d30 --- /dev/null +++ b/scheme/parsec-tpm/test_vars.go @@ -0,0 +1,39 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package parsec_tpm + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-parsec-tpm-bad-class-id.cbor + corimParsecTpmBadClassId []byte + + //go:embed test/corim/corim-parsec-tpm-bad-instance.cbor + corimParsecTpmBadInstance []byte + + //go:embed test/corim/corim-parsec-tpm-bad-multiple-keys.cbor + corimParsecTpmBadMultipleKeys []byte + + //go:embed test/corim/corim-parsec-tpm-bad-no-class.cbor + corimParsecTpmBadNoClass []byte + + //go:embed test/corim/corim-parsec-tpm-bad-no-class-id.cbor + corimParsecTpmBadNoClassId []byte + + //go:embed test/corim/corim-parsec-tpm-bad-no-digests.cbor + corimParsecTpmBadNoDigests []byte + + //go:embed test/corim/corim-parsec-tpm-bad-no-instance.cbor + corimParsecTpmBadNoInstance []byte + + //go:embed test/corim/corim-parsec-tpm-bad-no-pcr.cbor + corimParsecTpmBadNoPcr []byte + + //go:embed test/corim/corim-parsec-tpm-bad-pcr.cbor + corimParsecTpmBadPcr []byte + + //go:embed test/corim/corim-parsec-tpm-valid.cbor + corimParsecTpmValid []byte +) diff --git a/scheme/psa-iot/Makefile b/scheme/psa-iot/Makefile index 1551e931..bb8a54e5 100644 --- a/scheme/psa-iot/Makefile +++ b/scheme/psa-iot/Makefile @@ -7,9 +7,6 @@ SRCS := $(wildcard *.go) SUBDIR += plugin -# auto-generated -COPYRIGHT_FLAGS += --ignore */test_vectors.go - include ../../mk/common.mk include ../../mk/lint.mk include ../../mk/pkg.mk diff --git a/scheme/psa-iot/README.md b/scheme/psa-iot/README.md deleted file mode 100644 index bf939fc3..00000000 --- a/scheme/psa-iot/README.md +++ /dev/null @@ -1,36 +0,0 @@ -## Endorsement Store Interface - -### Reference Value - -```json -{ - "scheme": "PSA_IOT", - "type": "REFERENCE_VALUE", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "impl-id": "IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9Ig==", - "measurement-desc": "sha-256", - "measurement-type": "BL", - "measurement-value": "h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", - "version": "2.1.0" - } -} -``` - -### Trust Anchor - -```json -{ - "scheme": "PSA_IOT", - "type": "VERIFICATION_KEY", - "attributes": { - "hw-model": "RoadRunner", - "hw-vendor": "ACME", - "iak-pub": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6Vwqe7hy3O8Ypa+BUETLUjBNU3rEXVUyt9XHR7HJWLG7XTKQd9i1kVRXeBPDLFnfYru1/euxRnJM7H9UoFDLdA==", - "impl-id": "IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9Ig==", - "inst-id": "AUyj5PUL8kjDl4cCDWj/0FyIdndRvyZFypI/V6mL7NKW" - } -} -``` diff --git a/scheme/psa-iot/corim.go b/scheme/psa-iot/corim.go new file mode 100644 index 00000000..5780a644 --- /dev/null +++ b/scheme/psa-iot/corim.go @@ -0,0 +1,94 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package psa_iot + +import ( + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/services/scheme/common" +) + +const ProfileString = "http://arm.com/psa/iot/1" + +func validateEnvironment(env *comid.Environment, isTrustAnchor bool) error { + if env.Class == nil { + return errors.New("class missing") + } + + if env.Class.ClassID == nil { + return errors.New("class ID missing") + } + + if env.Class.ClassID.Type() != comid.ImplIDType { + return fmt.Errorf("class ID: expected psa.impl-id, got %s", env.Class.ClassID.Type()) + } + + if isTrustAnchor { + if env.Instance == nil { + return errors.New("instance not set for trust anchor") + } + + if env.Instance.Type() != comid.UEIDType { + return fmt.Errorf("instance: expected UEID, got %s", env.Instance.Type()) + } + + } else if env.Instance != nil { + return errors.New("instance set for reference value") + } + + return nil +} + +func validateCryptoKeys(keys []*comid.CryptoKey) error { + if len(keys) != 1 { + return fmt.Errorf("expected exactly one key but got %d", len(keys)) + } + + if keys[0].Type() != comid.PKIXBase64KeyType { + return fmt.Errorf("trust anchor must be a PKIX base64 key, found: %s", keys[0].Type()) + } + + return nil +} + +func validateMeasurements(measurements []comid.Measurement) error { + for i, mea := range measurements { + if mea.Key.Type() != comid.PSARefValIDType { + return fmt.Errorf("measurement %d key: expected psa.refval-id, got %s", i, mea.Key.Type()) + } + + if mea.Val.Digests == nil { + return fmt.Errorf("measurement %d value: no digests", i) + } + } + + return nil +} + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + validator := &common.TriplesValidator{ + TAEnviromentValidator: func(e *comid.Environment) error { + return validateEnvironment(e, true) + }, + RefValEnviromentValidator: func(e *comid.Environment) error { + return validateEnvironment(e, false) + }, + CryptoKeysValidator: validateCryptoKeys, + MeasurementsValidator: validateMeasurements, + } + + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/psa-iot/corim_extractor.go b/scheme/psa-iot/corim_extractor.go deleted file mode 100644 index 185ec7da..00000000 --- a/scheme/psa-iot/corim_extractor.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package psa_iot - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common/arm/platform" -) - -type CorimExtractor struct { - Profile string -} - -func (o CorimExtractor) RefValExtractor(rvs comid.ValueTriples) ([]*handler.Endorsement, error) { - refVals := make([]*handler.Endorsement, 0, len(rvs.Values)) - - for _, rv := range rvs.Values { - var classAttrs platform.ClassAttributes - var refVal *handler.Endorsement - var err error - - if o.Profile != "http://arm.com/psa/iot/1" { - return nil, fmt.Errorf( - "incorrect profile: %s for Scheme PSA_IOT", - o.Profile, - ) - } - - if err := classAttrs.FromEnvironment(rv.Environment); err != nil { - return nil, fmt.Errorf("could not extract PSA class attributes: %w", err) - } - - // Each measurement is encoded in a measurement-map of a CoMID - // reference-triple-record. Since a measurement-map can encode one or more - // measurements, a single reference-triple-record can carry as many - // measurements as needed, provided they belong to the same PSA RoT - // identified in the subject of the "reference value" triple. A single - // reference-triple-record SHALL completely describe the updatable PSA RoT. - for i, m := range rv.Measurements.Values { - if m.Key == nil { - return nil, fmt.Errorf("measurement key is not present") - } - - if !m.Key.IsSet() { - return nil, fmt.Errorf("measurement key is not set at index %d ", i) - } - - // Check which MKey is present and then decide which extractor to invoke - switch m.Key.Type() { - case comid.PSARefValIDType: - var swCompAttrs platform.SwCompAttributes - refVal, err = o.extractMeas(&swCompAttrs, m, classAttrs) - if err != nil { - return nil, fmt.Errorf("unable to extract measurement at index %d, %w", i, err) - } - default: - return nil, fmt.Errorf("unknown measurement key: %T", reflect.TypeOf(m.Key)) - } - refVals = append(refVals, refVal) - } - } - - if len(refVals) == 0 { - return nil, fmt.Errorf("no software components found") - } - - return refVals, nil -} - -func (o CorimExtractor) extractMeas( - obj platform.MeasurementExtractor, - m comid.Measurement, - class platform.ClassAttributes, -) (*handler.Endorsement, error) { - if err := obj.FromMeasurement(m); err != nil { - return nil, err - } - - refAttrs, err := obj.MakeRefAttrs(class) - if err != nil { - return &handler.Endorsement{}, fmt.Errorf("failed to create software component attributes: %w", err) - } - refVal := handler.Endorsement{ - Scheme: "PSA_IOT", - Type: handler.EndorsementType_REFERENCE_VALUE, - SubType: obj.GetRefValType(), - Attributes: refAttrs, - } - return &refVal, nil -} - -func (o CorimExtractor) TaExtractor(avk comid.KeyTriple) (*handler.Endorsement, error) { - // extract implementation ID - var classAttrs platform.ClassAttributes - if err := classAttrs.FromEnvironment(avk.Environment); err != nil { - return nil, fmt.Errorf("could not extract PSA class attributes: %w", err) - } - - // extract instance ID - var instanceAttrs platform.InstanceAttributes - if err := instanceAttrs.FromEnvironment(avk.Environment); err != nil { - return nil, fmt.Errorf("could not extract PSA instance-id: %w", err) - } - - // extract IAK pub - if len(avk.VerifKeys) != 1 { - return nil, errors.New("expecting exactly one IAK public key") - } - - iakPub := avk.VerifKeys[0] - if _, ok := iakPub.Value.(*comid.TaggedPKIXBase64Key); !ok { - return nil, fmt.Errorf("IAK does not appear to be a PEM key (%T)", iakPub.Value) - } - - taAttrs, err := makeTaAttrs(instanceAttrs, classAttrs, iakPub) - if err != nil { - return nil, fmt.Errorf("failed to create trust anchor attributes: %w", err) - } - - // note we do not need a subType for TA - ta := &handler.Endorsement{ - Scheme: "PSA_IOT", - Type: handler.EndorsementType_VERIFICATION_KEY, - Attributes: taAttrs, - } - - return ta, nil -} - -func makeTaAttrs( - i platform.InstanceAttributes, - c platform.ClassAttributes, - key *comid.CryptoKey, -) (json.RawMessage, error) { - taID := map[string]interface{}{ - "impl-id": c.ImplID, - "inst-id": []byte(i.InstID), - "iak-pub": key.String(), - } - - if c.Vendor != "" { - taID["hw-vendor"] = c.Vendor - } - - if c.Model != "" { - taID["hw-model"] = c.Model - } - - msg, err := json.Marshal(taID) - if err != nil { - return nil, fmt.Errorf("unable to marshal TA attributes: %w", err) - } - return msg, nil -} - -func (o *CorimExtractor) SetProfile(profile string) { - o.Profile = profile -} diff --git a/scheme/psa-iot/corim_test.go b/scheme/psa-iot/corim_test.go new file mode 100644 index 00000000..fd0db8a1 --- /dev/null +++ b/scheme/psa-iot/corim_test.go @@ -0,0 +1,55 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package psa_iot + +import ( + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "ok", + Input: corimPsaValid, + }, + { + Title: "bad wring class ID type", + Input: corimPsaBadClass, + Err: "class ID: expected psa.impl-id, got uuid", + }, + { + Title: "bad wring instance type", + Input: corimPsaBadInstance, + Err: "instance: expected UEID, got uuid", + }, + { + Title: "bad TA no instance", + Input: corimPsaBadTaNoInstance, + Err: "instance not set for trust anchor", + }, + { + Title: "bad RefVal instance", + Input: corimPsaBadRefvalInstance, + Err: "instance set for reference value", + }, + { + Title: "bad TA cert", + Input: corimPsaBadTaCert, + Err: "trust anchor must be a PKIX base64 key, found: pkix-base64-cert", + }, + { + Title: "bad RefVal uint mkey", + Input: corimPsaBadRefvalMkey, + Err: "measurement 1 key: expected psa.refval-id, got uint", + }, + { + Title: "bad RefVal mval no digests", + Input: corimPsaBadRefvalMval, + Err: "measurement 0 value: no digests", + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/psa-iot/endorsement_handler.go b/scheme/psa-iot/endorsement_handler.go deleted file mode 100644 index acb61e6a..00000000 --- a/scheme/psa-iot/endorsement_handler.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package psa_iot - -import ( - "errors" - - "mime" - - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common" -) - -type EndorsementHandler struct{} - -func (o EndorsementHandler) Init(params handler.EndorsementHandlerParams) error { - return nil // no-op -} - -func (o EndorsementHandler) Close() error { - return nil // no-op -} - -func (o EndorsementHandler) GetName() string { - return "corim (PSA profile)" -} - -func (o EndorsementHandler) GetAttestationScheme() string { - return SchemeName -} - -func (o EndorsementHandler) GetSupportedMediaTypes() []string { - return EndorsementMediaTypes -} - -func (o EndorsementHandler) Decode(data []byte, mediaType string, caCertPool []byte) (*handler.EndorsementHandlerResponse, error) { - extractor := &CorimExtractor{} - - if mediaType != "" { - mt, _, err := mime.ParseMediaType(mediaType) - if err != nil { - return nil, err - } - - // Use signed decoder for signed CoRIM - if mt == "application/rim+cose" { - return common.SignedCorimDecoder(data, extractor, caCertPool) - } - } - - // Default to unsigned CoRIM decoder - return common.UnsignedCorimDecoder(data, extractor) -} - -func (o EndorsementHandler) CoservRepackage(coservQuery string, resultSet []string) ([]byte, error) { - return nil, errors.New("PSA-IoT CoservRepackage not implemented") -} diff --git a/scheme/psa-iot/endorsement_handler_test.go b/scheme/psa-iot/endorsement_handler_test.go deleted file mode 100644 index b582a603..00000000 --- a/scheme/psa-iot/endorsement_handler_test.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package psa_iot - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDecoder_GetAttestationScheme(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetAttestationScheme() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetSupportedMediaTypes(t *testing.T) { - d := &EndorsementHandler{} - - expected := EndorsementMediaTypes - - actual := d.GetSupportedMediaTypes() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_Init(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Init(nil)) -} - -func TestDecoder_Close(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Close()) -} - -func TestDecoder_Decode_empty_data(t *testing.T) { - d := &EndorsementHandler{} - - emptyData := []byte{} - - expectedErr := `empty data` - - _, err := d.Decode(emptyData, "", nil) - - assert.EqualError(t, err, expectedErr) -} - -func TestDecoder_Decode_invalid_data(t *testing.T) { - d := &EndorsementHandler{} - - invalidCbor := []byte("invalid CBOR") - - expectedErr := `CBOR decoding failed` - - _, err := d.Decode(invalidCbor, "", nil) - - assert.ErrorContains(t, err, expectedErr) -} - -func TestDecoder_Decode_OK(t *testing.T) { - tvs := [][]byte{ - unsignedCorimComidPsaIakPubOne, - unsignedCorimComidPsaIakPubTwo, - unsignedCorimComidPsaRefValOne, - unsignedCorimComidPsaRefValThree, - unsignedCorimComidPsaRefValOnlyMandIDAttr, - } - - d := &EndorsementHandler{} - - for _, tv := range tvs { - _, err := d.Decode(tv, "", nil) - assert.NoError(t, err) - } -} - -func TestDecoder_Decode_negative_tests(t *testing.T) { - tvs := []struct { - desc string - input []byte - expectedErr string - }{ - { - desc: "multiple verification keys for an instance", - input: unsignedCorimComidPsaMultIak, - expectedErr: `bad key in CoMID at index 0: expecting exactly one IAK public key`, - }, - { - desc: "multiple digests in the same measurement", - input: unsignedCorimComidPsaRefValMultDigest, - expectedErr: "bad software component in CoMID at index 0: unable to extract measurement at index 0, expecting exactly one digest", - }, - { - desc: "missing measurement identifier", - input: unsignedCorimComidPsaRefValNoMkey, - expectedErr: `bad software component in CoMID at index 0: measurement key is not present`, - }, - { - desc: "no implementation id specified in the measurement", - input: unsignedCorimComidPsaRefValNoImplID, - expectedErr: `bad software component in CoMID at index 0: could not extract PSA class attributes: could not extract implementation-id from class-id: class-id type is: *comid.TaggedUUID`, - }, - { - desc: "no instance id specified in the verification key triple", - input: unsignedCorimComidPsaIakPubNoUeID, - expectedErr: `bad key in CoMID at index 0: could not extract PSA instance-id: expecting instance in environment`, - }, - { - desc: "no implementation id specified in the verification key triple", - input: unsignedCorimComidPsaIakPubNoImplID, - expectedErr: `bad key in CoMID at index 0: could not extract PSA class attributes: could not extract implementation-id from class-id: class-id type is: *comid.TaggedUUID`, - }} - - for _, tv := range tvs { - t.Run(tv.desc, func(t *testing.T) { - d := &EndorsementHandler{} - _, err := d.Decode(tv.input, "", nil) - assert.EqualError(t, err, tv.expectedErr) - }) - } -} diff --git a/scheme/psa-iot/evidence_handler.go b/scheme/psa-iot/evidence_handler.go deleted file mode 100644 index f574d34a..00000000 --- a/scheme/psa-iot/evidence_handler.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package psa_iot - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "fmt" - "log" - - "github.com/veraison/ear" - "github.com/veraison/psatoken" - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" - "github.com/veraison/services/scheme/common" - "github.com/veraison/services/scheme/common/arm" -) - -type EvidenceHandler struct{} - -func (s EvidenceHandler) GetName() string { - return "psa-evidence-handler" -} - -func (s EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func (s EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - psaToken, err := psatoken.DecodeAndValidateEvidenceFromCOSE(token.Data) - - if err != nil { - return nil, handler.BadEvidence(err) - } - - claimsSet, err := common.ClaimsToMap(common.PsaPlatformWrapper{psaToken.Claims}) // nolint:govet - if err != nil { - return nil, handler.BadEvidence(err) - } - - return claimsSet, nil -} - -func (s EvidenceHandler) ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - endorsementsStrings []string, -) error { - psaToken, err := psatoken.DecodeAndValidateEvidenceFromCOSE(token.Data) - if err != nil { - return handler.BadEvidence(err) - } - - psaNonce, err := psaToken.Claims.GetNonce() - if err != nil { - return handler.BadEvidence(err) - } - if !bytes.Equal(psaNonce, token.Nonce) { - return handler.BadEvidence( - "freshness: psa-nonce (%s) does not match session nonce (%s)", - hex.EncodeToString(psaNonce), - hex.EncodeToString(token.Nonce), - ) - } - - pk, err := arm.GetPublicKeyFromTA(SchemeName, trustAnchors[0]) - if err != nil { - return fmt.Errorf("could not get public key from trust anchor: %w", err) - } - - if err = psaToken.Verify(pk); err != nil { - return handler.BadEvidence(err) - } - log.Println("\n Token Signature Verified") - return nil -} - -func (s EvidenceHandler) AppraiseEvidence( - ec *proto.EvidenceContext, endorsementsStrings []string, -) (*ear.AttestationResult, error) { - var endorsements []handler.Endorsement // nolint:prealloc - - result := handler.CreateAttestationResult(SchemeName) - - for i, e := range endorsementsStrings { - var endorsement handler.Endorsement - - if err := json.Unmarshal([]byte(e), &endorsement); err != nil { - return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err) - } - - endorsements = append(endorsements, endorsement) - } - - err := populateAttestationResult(result, ec.Evidence.AsMap(), endorsements) - - return result, err -} - -func populateAttestationResult( - result *ear.AttestationResult, - evidence map[string]interface{}, - endorsements []handler.Endorsement, -) error { - claims, err := common.MapToPSAClaims(evidence) - if err != nil { - return handler.BadEvidence(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() - if err != nil { - return handler.BadEvidence(err) - } - - lifeCycle := psatoken.LifeCycleToState(rawLifeCycle) - if lifeCycle == psatoken.StateSecured || lifeCycle == psatoken.StateNonPSAROTDebug { - 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 - } - - match := arm.MatchSoftware(SchemeName, claims, endorsements) - if match { - appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim - log.Println("\n matchSoftware Success") - - } else { - appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim - log.Println("\n matchSoftware Failed") - } - - appraisal.UpdateStatusFromTrustVector() - - appraisal.VeraisonAnnotatedEvidence = &evidence - - return nil -} diff --git a/scheme/psa-iot/evidence_handler_test.go b/scheme/psa-iot/evidence_handler_test.go deleted file mode 100644 index 8e956b45..00000000 --- a/scheme/psa-iot/evidence_handler_test.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package psa_iot - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/ear" - "github.com/veraison/services/proto" -) - -var testNonce = []byte{ - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, - 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, -} - -func Test_ExtractVerifiedClaimsInteg_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/psaintegtoken.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-integ-endorsements.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - Nonce: testNonce, - } - ta := string(taEndValBytes) - _, err = handler.ExtractClaims(&token, []string{ta}) - - require.NoError(t, err) - -} - -func Test_ExtractVerifiedClaims_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/psa-token.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsements.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - ta := string(taEndValBytes) - claims, err := handler.ExtractClaims(&token, []string{ta}) - - require.NoError(t, err) - assert.Equal(t, "PSA_IOT_PROFILE_1", claims["psa-profile"].(string)) - - swComponents := claims["psa-software-components"].([]interface{}) - assert.Len(t, swComponents, 4) - assert.Equal(t, "BL", swComponents[0].(map[string]interface{})["measurement-type"].(string)) -} - -func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/psa-token.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsements.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - - ta := string(taEndValBytes) - err = handler.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - - assert.NoError(t, err) -} - -func Test_ValidateEvidenceIntegrity_BadKey(t *testing.T) { - tvs := []struct { - desc string - input string - expectedErr string - }{ - { - desc: "invalid public key", - input: "test/ta-bad-key.json", - expectedErr: `could not get public key from trust anchor: could not decode subject public key info: unable to parse public key: asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:1 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} AlgorithmIdentifier @2`, - }, - { - desc: "bad pem key header", - input: "test/ta-bad-key-header.json", - expectedErr: `could not get public key from trust anchor: could not decode subject public key info: could not extract trust anchor PEM block`, - }, - { - desc: "incorrect key type", - input: "test/ta-bad-key-private-key.json", - expectedErr: "could not get public key from trust anchor: could not decode subject public key info: unsupported key type: \"PRIVATE KEY\"", - }, - } - - for _, tv := range tvs { - tokenBytes, err := os.ReadFile("test/psa-token.cbor") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile(tv.input) - require.NoError(t, err) - h := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - ta := string(taEndValBytes) - err = h.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - - assert.EqualError(t, err, tv.expectedErr) - } -} - -func Test_AppraiseEvidence_ok(t *testing.T) { - extractedBytes, err := os.ReadFile("test/extracted.json") - require.NoError(t, err) - - var ec proto.EvidenceContext - err = json.Unmarshal(extractedBytes, &ec) - require.NoError(t, err) - - endorsementsBytes, err := os.ReadFile("test/endorsements.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - result, err := handler.AppraiseEvidence(&ec, []string{string(endorsementsBytes)}) - require.NoError(t, err) - - attestation := result.Submods["PSA_IOT"] - - assert.Equal(t, ear.TrustTierAffirming, *attestation.Status) -} - -func Test_AppraiseEvidenceMultEndorsement_ok(t *testing.T) { - extractedBytes, err := os.ReadFile("test/extracted.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/mult-endorsements.json") - require.NoError(t, err) - err = json.Unmarshal(endorsementsBytes, &endorsemementsArray) - require.NoError(t, err) - - handler := &EvidenceHandler{} - - result, err := handler.AppraiseEvidence(&ec, endorsemementsArray) - require.NoError(t, err) - - attestation := result.Submods["PSA_IOT"] - - assert.Equal(t, ear.TrustTierAffirming, *attestation.Status) -} diff --git a/scheme/psa-iot/plugin/Makefile b/scheme/psa-iot/plugin/Makefile index 33a74ffc..fffea706 100644 --- a/scheme/psa-iot/plugin/Makefile +++ b/scheme/psa-iot/plugin/Makefile @@ -1,11 +1,11 @@ +# Copyright 2021 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += endorsement-handler - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-psa-iot.plugin +GOPKG := github.com/veraison/services/scheme/psa-iot +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/psa-iot/plugin/combined/Makefile b/scheme/psa-iot/plugin/combined/Makefile deleted file mode 100644 index 9eb65ba1..00000000 --- a/scheme/psa-iot/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2021 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/psa.plugin -GOPKG := github.com/veraison/services/scheme/psa-iot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/psa-iot/plugin/combined/main.go b/scheme/psa-iot/plugin/combined/main.go deleted file mode 100644 index 48b1bc26..00000000 --- a/scheme/psa-iot/plugin/combined/main.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/psa-iot" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/psa-iot/plugin/endorsement-handler/Makefile b/scheme/psa-iot/plugin/endorsement-handler/Makefile deleted file mode 100644 index a7f89072..00000000 --- a/scheme/psa-iot/plugin/endorsement-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2021 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/psa-endorsement-handler.plugin -GOPKG := github.com/veraison/services/scheme/psa-iot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/psa-iot/plugin/evidence-handler/Makefile b/scheme/psa-iot/plugin/evidence-handler/Makefile deleted file mode 100644 index 2f04ac9f..00000000 --- a/scheme/psa-iot/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2021 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/psa-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/psa-iot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/psa-iot/plugin/evidence-handler/main.go b/scheme/psa-iot/plugin/evidence-handler/main.go deleted file mode 100644 index 97d39900..00000000 --- a/scheme/psa-iot/plugin/evidence-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/psa-iot" -) - -func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - plugin.Serve() -} diff --git a/scheme/psa-iot/plugin/endorsement-handler/main.go b/scheme/psa-iot/plugin/main.go similarity index 61% rename from scheme/psa-iot/plugin/endorsement-handler/main.go rename to scheme/psa-iot/plugin/main.go index 3fc05f7d..f5f027c3 100644 --- a/scheme/psa-iot/plugin/endorsement-handler/main.go +++ b/scheme/psa-iot/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) plugin.Serve() } diff --git a/scheme/psa-iot/plugin/store-handler/Makefile b/scheme/psa-iot/plugin/store-handler/Makefile deleted file mode 100644 index 174feb7e..00000000 --- a/scheme/psa-iot/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/psa-store-handler.plugin -GOPKG := github.com/veraison/services/scheme/psa-iot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/psa-iot/plugin/store-handler/main.go b/scheme/psa-iot/plugin/store-handler/main.go deleted file mode 100644 index abf120ba..00000000 --- a/scheme/psa-iot/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/psa-iot" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/psa-iot/scheme.go b/scheme/psa-iot/scheme.go index ee57a9b0..61d1fe14 100644 --- a/scheme/psa-iot/scheme.go +++ b/scheme/psa-iot/scheme.go @@ -1,25 +1,288 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package psa_iot -const ( - SchemeName = "PSA_IOT" +import ( + "bytes" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/psatoken" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + "github.com/veraison/services/scheme/common" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" ) -var EndorsementMediaTypes = []string{ - // Unsigned CoRIM profile - `application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"`, - // Signed CoRIM profile - `application/rim+cose; profile="http://arm.com/psa/iot/1"`, +var Descriptor = handler.SchemeDescriptor{ + Name: "PSA_IOT", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + }, + EvidenceMediaTypes: []string{ + "application/psa-attestation-token", + `application/eat-cwt; profile="http://arm.com/psa/2.0.0"`, + `application/eat+cwt; eat_profile="tag:psacertified.org,2023:psa#tfm"`, + `application/eat+cwt; eat_profile="tag:psacertified.org,2019:psa#legacy"`, + }, +} + +type Implementation struct { + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), + } +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + psaToken, err := psatoken.DecodeAndValidateEvidenceFromCOSE(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + implIDbytes, err := psaToken.Claims.GetImplID() + if err != nil { + return nil, err + } + + instIDbytes, err := psaToken.Claims.GetInstID() + if err != nil { + return nil, err + } + + classID, err := comid.NewImplIDClassID(implIDbytes) + if err != nil { + return nil, err + } + + instanceID, err := comid.NewUEIDInstance(instIDbytes) + if err != nil { + return nil, err + } + + return []*comid.Environment{ + { + Class: &comid.Class{ClassID: classID}, + Instance: instanceID, + }, + }, nil +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + numTAs := len(trustAnchors) + if numTAs != 1 { + return nil, fmt.Errorf("expected exactly 1 trust anchor; got %d", numTAs) + } + + return []*comid.Environment{ + { + Class: trustAnchors[0].Environment.Class, + }, + }, nil +} + +func (o *Implementation) ValidateComid(c *comid.Comid) error { + return nil +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + psaToken, err := psatoken.DecodeAndValidateEvidenceFromCOSE(evidence.Data) + if err != nil { + return nil, handler.BadEvidence(err) + } + + claims, err := common.ToMapViaJSON(psaToken.Claims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + return claims, nil +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + pk, err := common.ExtractPublicKeyFromTrustAnchors(trustAnchors) + if err != nil { + return fmt.Errorf("could not get public key from trust anchors: %w", err) + } + + psaToken, err := psatoken.DecodeAndValidateEvidenceFromCOSE(evidence.Data) + if err != nil { + return handler.BadEvidence(err) + } + + psaNonce, err := psaToken.Claims.GetNonce() + if err != nil { + return handler.BadEvidence(err) + } + + if !bytes.Equal(psaNonce, evidence.Nonce) { + return handler.BadEvidence( + "freshness: psa-nonce (%s) does not match session nonce (%s)", + hex.EncodeToString(psaNonce), + hex.EncodeToString(evidence.Nonce), + ) + } + + if err = psaToken.Verify(pk); err != nil { + return handler.BadEvidence(err) + } + o.logger.Info("Token signature verified.") + + return nil } -var EvidenceMediaTypes = []string{ - "application/psa-attestation-token", - `application/eat-cwt; profile="http://arm.com/psa/2.0.0"`, - `application/eat+cwt; eat_profile="tag:psacertified.org,2023:psa#tfm"`, - `application/eat+cwt; eat_profile="tag:psacertified.org,2019:psa#legacy"`, +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + appraisal := result.Submods[Descriptor.Name] + + psaClaims, err := convertMapToPSAClaims(claims) + if err != nil { + return result, handler.BadEvidence(err) + } + + rawLifeCycle, err := psaClaims.GetSecurityLifeCycle() + if err != nil { + return result, handler.BadEvidence(err) + } + + // once the signature on the token is verified, we can claim the HW is + // authentic + appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim + + lifeCycle := psatoken.LifeCycleToState(rawLifeCycle) + if lifeCycle == psatoken.StateSecured || lifeCycle == psatoken.StateNonPSAROTDebug { + 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 + } + + matched, err := matchClaimsToReferenceValues(o.logger, psaClaims, endorsements) + if err != nil { + return result, err + } + + if matched { + appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim + o.logger.Info("Matched software.") + } else { + appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim + o.logger.Info("Failed to match software.") + } + + appraisal.UpdateStatusFromTrustVector() + appraisal.VeraisonAnnotatedEvidence = &claims + + return result, nil } -var CoservMediaTypes = []string{ - `application/coserv+cbor; profile="tag:psacertified.org,2023:psa#tfm"`, +func convertMapToPSAClaims(m map[string]any) (psatoken.IClaims, error) { + data, err := json.Marshal(m) + if err != nil { + return nil, err + } + + return psatoken.DecodeAndValidateClaimsFromJSON(data) +} + +func matchClaimsToReferenceValues( + logger *zap.SugaredLogger, + claims psatoken.IClaims, + endorsements []*comid.ValueTriple, +) (bool, error) { + referenceValues := make(map[string][2]string) + for _, triple := range endorsements { + for _, measurement := range triple.Measurements.Values { + refValID, err := measurement.Key.GetPSARefValID() + if err != nil { + return false, err + } + + if measurement.Val.Digests == nil { + return false, errors.New("no digests in reference value measurement") + } + + numDigests := len(*measurement.Val.Digests) + if numDigests != 1 { + return false, fmt.Errorf( + "expected exactly 1 digest in measurement; found %d", + numDigests, + ) + } + + encoded := base64.StdEncoding.EncodeToString((*measurement.Val.Digests)[0].HashValue) + referenceValues[encoded] = [2]string{*refValID.Label, *refValID.Version} + } + } + + swComponents, err := claims.GetSoftwareComponents() + if err != nil { + return false, handler.BadEvidence(err) + } + + for i, swComp := range swComponents { + mval, err := swComp.GetMeasurementValue() + if err != nil { + return false, handler.BadEvidence(fmt.Errorf("S/W comp. %d value: %w", i, err)) + } + mvalEncoded := base64.StdEncoding.EncodeToString(mval) + + mtype, err := swComp.GetMeasurementType() + if err != nil { + return false, handler.BadEvidence(fmt.Errorf("S/W comp. %d type: %w", i, err)) + } + + mversion, err := swComp.GetVersion() + if err != nil { + return false, handler.BadEvidence(fmt.Errorf("S/W comp. %d version: %w", i, err)) + } + + rvInfo, matched := referenceValues[mvalEncoded] + if !matched { + logger.Debugf("S/W comp. %d measurement failed to match", i) + return false, nil + } + logger.Debugf("S/W comp. %d measurement matched", i) + refValLabel := rvInfo[0] + refValVersion := rvInfo[1] + + typeMatched := refValLabel == "" || mtype == refValLabel + versionMatched := refValVersion == "" || mversion == refValVersion + logger.Debugf("S/W comp. %d type matched: %t, version matched: %t", i, typeMatched, versionMatched) + + if !typeMatched || !versionMatched { + return false, nil + } + } + + return true, nil } diff --git a/scheme/psa-iot/store_handler.go b/scheme/psa-iot/store_handler.go deleted file mode 100644 index 47380840..00000000 --- a/scheme/psa-iot/store_handler.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2021-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package psa_iot - -import ( - "github.com/veraison/psatoken" - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" - "github.com/veraison/services/scheme/common/arm" -) - -type StoreHandler struct{} - -func (s StoreHandler) GetName() string { - return "psa-store-handler" -} - -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -func (s StoreHandler) SynthKeysFromRefValue( - tenantID string, - refValue *handler.Endorsement, -) ([]string, error) { - return arm.SynthKeysForPlatform(SchemeName, tenantID, refValue) -} - -func (s StoreHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) { - return arm.SynthKeysFromTrustAnchors(SchemeName, tenantID, ta) -} - -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - psaToken, err := psatoken.DecodeAndValidateEvidenceFromCOSE(token.Data) - if err != nil { - return []string{""}, handler.BadEvidence(err) - } - - claims := psaToken.Claims - - taID, err := arm.GetTrustAnchorID(SchemeName, token.TenantId, claims) - if err != nil { - return []string{""}, err - } - - return []string{taID}, nil -} - -func (s StoreHandler) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - return arm.GetPlatformReferenceIDs(SchemeName, tenantID, claims) -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - return []string{"TODO"}, nil -} diff --git a/scheme/psa-iot/store_handler_test.go b/scheme/psa-iot/store_handler_test.go deleted file mode 100644 index 76072a2c..00000000 --- a/scheme/psa-iot/store_handler_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package psa_iot - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -func Test_GetTrustAnchorIDs_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/psa-token.cbor") - require.NoError(t, err) - - token := proto.AttestationToken{ - TenantId: "1", - Data: tokenBytes, - Nonce: testNonce, - } - - expectedTaID := "PSA_IOT://1/BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=/AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY" - - handler := &StoreHandler{} - - taIDs, err := handler.GetTrustAnchorIDs(&token) - require.NoError(t, err) - assert.Equal(t, 1, len(taIDs)) - assert.Equal(t, expectedTaID, taIDs[0]) -} - -func Test_GetRefValueIDs_ok(t *testing.T) { - rawToken, err := os.ReadFile("test/psa-token.json") - require.NoError(t, err) - - claims := make(map[string]interface{}) - err = json.Unmarshal(rawToken, &claims) - require.NoError(t, err) - - - expectedRefvalIDs := []string{"PSA_IOT://1/BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg="} - - scheme := &StoreHandler{} - refvalIDs, err := scheme.GetRefValueIDs("1", nil, claims) - require.NoError(t, err) - assert.Equal(t, expectedRefvalIDs, refvalIDs) -} - -func Test_SynthKeysFromTrustAnchor_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/ta-endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "PSA_IOT://1/76543210fedcba9817161514131211101f1e1d1c1b1a1918/Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromTrustAnchor("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) - -} - -func Test_SynthKeysFromRefValue_ok(t *testing.T) { - endorsementsBytes, err := os.ReadFile("test/endorsements.json") - require.NoError(t, err) - - var endors handler.Endorsement - err = json.Unmarshal(endorsementsBytes, &endors) - require.NoError(t, err) - expectedKey := "PSA_IOT://1/76543210fedcba9817161514131211101f1e1d1c1b1a1918" - - scheme := &StoreHandler{} - key_list, err := scheme.SynthKeysFromRefValue("1", &endors) - require.NoError(t, err) - assert.Equal(t, expectedKey, key_list[0]) -} diff --git a/scheme/psa-iot/test/corim/build-test-vectors.sh b/scheme/psa-iot/test/corim/build-test-vectors.sh deleted file mode 100755 index c785b40b..00000000 --- a/scheme/psa-iot/test/corim/build-test-vectors.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -set -eu -set -o pipefail - -THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -GEN_CORIM="$THIS_DIR/../../../common/scripts/gen-corim" - -CORIM_TEMPLATE=corimMini - -COMID_TEMPLATES=( - ComidPsaIakPubOne - ComidPsaIakPubTwo - ComidPsaRefValOne - ComidPsaRefValThree - ComidPsaMultIak - ComidPsaRefValMultDigest - ComidPsaRefValOnlyMandIDAttr - ComidPsaRefValNoMkey - ComidPsaRefValNoImplID - ComidPsaIakPubNoUeID - ComidPsaIakPubNoImplID -) - -for comid in "${COMID_TEMPLATES[@]}" -do - "$GEN_CORIM" "$THIS_DIR" "$comid" "$CORIM_TEMPLATE" "unsigned" -done - -echo "done" diff --git a/scheme/psa-iot/test/corim/compile-endorsements.sh b/scheme/psa-iot/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..c039ac9f --- /dev/null +++ b/scheme/psa-iot/test/corim/compile-endorsements.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p psa_iot "$THIS_DIR"/corim-*.cbor diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoImplID.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-class.cbor similarity index 56% rename from scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoImplID.cbor rename to scheme/psa-iot/test/corim/corim-psa-bad-class.cbor index 66d9c66432b5548431cca07832d4c7dcf88c28b9..017cc750c76109dabcdf6f5740ea939f2b2d715d 100644 GIT binary patch delta 93 zcmZo-e!^sWlkw|fh6+^!D9{DbP{PbK5zKMeT%$FDg_|VnPCeqX20^Lrp~>Omt)}0oWjPXmoUNb2=|CVPkD&E@gOO zZE$R50)qen0tBH0fr6p{qyX3@P~B!>@ChhH0hVi6o~KR=GI9cAMomKl00aP$Z1`q| BH5~u| diff --git a/scheme/psa-iot/test/corim/corim-psa-bad-instance.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-instance.cbor new file mode 100644 index 0000000000000000000000000000000000000000..f883c9c88869ad83e246789ffd7d16e52d33db36 GIT binary patch literal 355 zcmcb~_;oQug{lD*=z?e{VP={LX2Il)85?gh{)%K2SFK3mI-QMMNkhCg-N=X66>;q~@mPl_ZvA=I7~Vroc@#WW1po zQ2V{mZxxH1#h(4n-m=#fJ~rND(yG{?3j$8A?w)=M0ijMlp3Vy1u909tE?>9oa@X=m z5AXaa&#Ei~XUD)uPbk~PF)-OBFx}DBEUdgR)jXrp*xw?uAW_>X)HTE>G|R~^)VRns zA}qAB#4^Go$lSv#+{fKKBE&l|#WK?{J1i(7)hWQm$1N`{vZ&NhKeeFXyJdWqh~ z>n;bM|LD{$#hl?!N*<}BnS5f%=>5W}4vKbdLH8wFuC@fz3 zT=c`4aIfOSKlkm(KiGDxPNSN literal 0 HcmV?d00001 diff --git a/scheme/psa-iot/test/corim/corim-psa-bad-refval-mkey.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-refval-mkey.cbor new file mode 100644 index 0000000000000000000000000000000000000000..8d3051095d83d18bfdd2364675d2cc5ef0f070bb GIT binary patch literal 281 zcmcb~_;oQug{lD*=z?e{VP={LX2Iml85?gh{)#xgh;bo9fb;Ih^?Hfk#_KKzpa1C8 zEyl8tp|NQp!$O9eOc4P*}5D@c5HkibbqJHc!q;sYE?oWVy~J`|rGp!tYOS?0S*SxR9x_i7`T< z-KqbmQiH7_TU_-yn-BI+N;%UEpFXJGTg87b;mCQ_wMCK3p_81q%4dmGFjq)ql#~=$>FXyJLM32rZ@)W zhp?m?=o#vnutq4X*)4ed$t}eq)*zcF=cH7k9xk$6XOsPRUPa;er#E)J$Yxx~c#}y( m`Z6B_2rx5ONMw|h6jkz^3eg46xzxv|E=P%y8^1Khj zxJ_S|ZQrDAdb)^A9t z`iT3>?>=$=_}hQ}?f0L)d9}KK{~xcP7UTp;`;g%bOX4L4SlqJ}Q6)+67lwgwpMyz) zAeUH>1E6xgz?f&jl%h4ObC9XPwgc3}>b~qtfdpKeg+O8us56Dgf)M8Qxu{Elo-hdX z{9BF>zw#-7x>p|oIH-!l%(K8mV6Hh33@U>;V?Z=x;5zrv-JVo^m>At>9bFf=Np|do zvsEYw0Jk|fO^QwMVfW}fp$Gy4Z;~Cf}6x5*3?RxR7)aM%U(2AUAqsP#>US! zFG9{Dx#!kH=r&(2_)WZjV! z#ZH>2rHe<~8L0x=`>r8x+s5$#92k&O;K_l>_m4dX)=WZgO?2cBqah8oOWzjSVIjYx zHCE?Ix-$v|K^5ZY=t8ky`$@*ZyysE5oLn9b7Mgi%u>cJ3*Ge5*D5)e>Y-D?{5}OsK zpHX#_1V~-%bhfk8{h~pIjp3eU1-Dz@)?4j%j+$jB z8Nv#w+@dKEy`w3`H@dIchlS*8wcUe z7KGPOZ_5p^gjO|HCt{DLD;X3vAyi}~^>T5j6Oqo!i_V_f1`sBn$tV+Jt)MN4OB=0J z+z<9i-x$=#W_yjKqTV zy%|sWrS@dOFDKz*P<2?IZ=|MCdU1g2*{|a0Qgat9qjYs&HXc=iINrg zXm<4|(v>9-{ai2R&=uN-w7Ztt8UC*6Ng}6GPdwsh|8lw&ODNzbi6OUXcc`N$vN)~&IM>n$}!X@C8sd)j1G}8p3`Ao$O$5@=@Z*c%z(#0gHT(k z;xw^O6KP;apo{1OPfr9A-VIX1=DG`^nR(f1#U|CGh*z)(rFYBC=6I`w&RxLq2`r-V z7^jTlpas|`A(ic(hAR;#eNkC%Qg-0lF{6O&-2zKQxExCA781ttz!?^l+ahxH(I@Du zvJR@i9d1d*-QGdw=C9@9J#>-pqV9J=7kQ88|EDh4JlL;;L~4$ZAz8h>iDX?hhvmf2 z>yp6D<#1$&t%8td&Q~f!Ukr>SXhP5#KnA4UoM}?lLpNoKE)#?y-40W=Iq2Cwb8hGo z$~Ir!x*<3qr!3g5(|)AX%FUta$@y02P|#qDF$6=uU9-?iz{ibCRAcyzTe? zQb;)(?~&`W>D2j5$$M9(jvdZ;%Ce8Mi`5rZ6V(L;oW1I$Fd@udU9TbTA2&G;4@r&T z>-roaWMqf|UP3|^g>9_v_t9i9CIEt{SPL+7Huf$w-;=?*DcM38(YVCBUTEtcCv>fp zkr76=`ny2gT#JG?lz$}-GE3(7& zZA*u~R)~L+6U##8#-@b~3mI-QMMNkhCg-N=X66>;q~@mPl_ZvA=I7~Vroc@#Y`n>& zRk1-A1e{#mJ^d5{LY;g(ofW)YBf)}PzHZs&uH}&)-uY3URapkkj)9S$P_~O>V6sbK zx}&RESb1Tpc}AtNzeQw0qPA10Ylu&1mXlwoagl38SZHO5WrRnNxrbM{kGpw9h<9L$ zWu{?vSWrZ&Q-F()TV7gZQK_MRYH3AKo|mt=hh=EKn~P71qpd9$*a@zFF6gdeu8_zm bDJihh*H0|U)l1IL)h{Sc)X&T>(KiGD24ZAr literal 0 HcmV?d00001 diff --git a/scheme/psa-iot/test/corim/corim-psa-valid.cbor b/scheme/psa-iot/test/corim/corim-psa-valid.cbor new file mode 100644 index 0000000000000000000000000000000000000000..130da979575cf2c74eaa0d1930d2d402eb1bec5e GIT binary patch literal 1017 zcmcb~_;oQug{lD*=z?e{VP={LX2IkP8Jli0{)%KwUd)i1ny2gT#JG?lzLM32COP@Aq#EfN>KU*`D6H8nc>KvN#Uj=qnV9zaOAw|aj4lT0YUj8EUAWi z#(JhCn9h{kG_!Nt->LpZyVmO;^FH+GgKVa*?{m$zR}KAnGaKz;raOX7Hvqcbgap$U zFMTfh;Y_$!@!_BQc4r^*H~N2dTeU@z%b}B;x5{UURDc4S$q_lA&2qW8B0F5)wsh!g zh4?2qu`Fb6YFb2WKr`NCQj1VzJokECb*K7brMh6|^Ktz0)h4?`w63di9kAbX&+Lu9 zC`aQ>CasE%x**`>>h9^M5D@C*8fXZ?$wJk$a&D`_KJj(Um!;PY%62nT0tJ2dWJj-ouxxj94^>aaY z7BCzZ6PMr^QyiUrU750i@)J{nO7rqki=ZLnv-rtZ?oS?vr?)flX8gYp(@|C)xL?in z)Fk`xmECVHO#_F_2CxIj4;izt^1@W}j7npFi^zgRZKqJz5TDR2C%;hRBG-tp(8?0a z2#+9h53g_^ck_r4@4ytxOvCK3pomnb02d#(ytK%oQbYaJ(u$xwFJE&H%g}r`7oQYI iJORU8A(2s1QedU8pIDTumz+Zz3kRiZ%_v3oKL~rADmxIrLbm|skYFx~a>FDh1s^C+SqQ`hcp(LZE zq@dVJUq3N9H&rjSA~ClhCzYw0fsu)2Awy%+LWac*H<=fs{GbvD_5=T#Jbe|lrri)_Y)OpQ&95en^2{YRA=Yz^7ss?XVcuzym@ UnP&L(LG|7${(A{W&Z`~=08@=u6951J diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValThree.json b/scheme/psa-iot/test/corim/src/ComidPsaRefValThree.json deleted file mode 100644 index 22a7d24a..00000000 --- a/scheme/psa-iot/test/corim/src/ComidPsaRefValThree.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "lang": "en-GB", - "tag-identity": { - "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", - "version": 0 - }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], - "triples": { - "reference-values": [ - { - "environment": { - "class": { - "id": { - "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" - } - }, - "measurements": [ - { - "key": { - "type": "psa.refval-id", - "value": { - "label": "BL", - "version": "2.1.0", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } - }, - "value": { - "digests": [ - "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" - ] - } - }, - { - "key": { - "type": "psa.refval-id", - "value": { - "label": "PRoT", - "version": "1.3.5", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } - }, - "value": { - "digests": [ - "sha-256:AmOCmYm2/ZVPcrqvL8ZLwuLwHWktTecphuqAj26ZgT8=" - ] - } - }, - { - "key": { - "type": "psa.refval-id", - "value": { - "label": "ARoT", - "version": "0.1.4", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } - }, - "value": { - "digests": [ - "sha-256:o6XnFfDMV0pzw/m+u2vCTzL/1bZ7OHJEwskJ2neaFHg=" - ] - } - } - ] - } - ] - } -} diff --git a/scheme/psa-iot/test/corim/src/ComidPsaIakPubNoImplID.json b/scheme/psa-iot/test/corim/src/comid-bad-class.json similarity index 74% rename from scheme/psa-iot/test/corim/src/ComidPsaIakPubNoImplID.json rename to scheme/psa-iot/test/corim/src/comid-bad-class.json index dc6b555a..789ebf35 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaIakPubNoImplID.json +++ b/scheme/psa-iot/test/corim/src/comid-bad-class.json @@ -4,17 +4,6 @@ "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "attester-verification-keys": [ { @@ -23,10 +12,7 @@ "id": { "type": "uuid", "value": "DD6661F0-0928-4401-966B-589EA74E3272" - }, - "model": "FMC", - "layer": 0, - "index": 0 + } }, "instance": { "type": "ueid", diff --git a/scheme/psa-iot/test/corim/src/ComidPsaIakPubNoUeID.json b/scheme/psa-iot/test/corim/src/comid-bad-instance.json similarity index 59% rename from scheme/psa-iot/test/corim/src/ComidPsaIakPubNoUeID.json rename to scheme/psa-iot/test/corim/src/comid-bad-instance.json index 8094a8a2..61f80ec4 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaIakPubNoUeID.json +++ b/scheme/psa-iot/test/corim/src/comid-bad-instance.json @@ -4,17 +4,6 @@ "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "attester-verification-keys": [ { @@ -23,15 +12,17 @@ "id": { "type": "psa.impl-id", "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + } + }, + "instance": { + "type": "uuid", + "value": "7df7714e-aa04-4638-bcbf-434b1dd720f1" } }, "verification-keys": [ { "type": "pkix-base64-key", - "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6Vwqe7hy3O8Ypa+BUETLUjBNU3rEXVUyt9XHR7HJWLG7XTKQd9i1kVRXeBPDLFnfYru1/euxRnJM7H9UoFDLdA==\n-----END PUBLIC KEY-----" } ] } diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValOnlyMandIDAttr.json b/scheme/psa-iot/test/corim/src/comid-bad-refval-instance.json similarity index 67% rename from scheme/psa-iot/test/corim/src/ComidPsaRefValOnlyMandIDAttr.json rename to scheme/psa-iot/test/corim/src/comid-bad-refval-instance.json index 7e397360..c3404a3e 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaRefValOnlyMandIDAttr.json +++ b/scheme/psa-iot/test/corim/src/comid-bad-refval-instance.json @@ -4,17 +4,6 @@ "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { @@ -23,9 +12,11 @@ "id": { "type": "psa.impl-id", "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + } + }, + "instance": { + "type": "ueid", + "value": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" } }, "measurements": [ @@ -33,12 +24,14 @@ "key": { "type": "psa.refval-id", "value": { + "label": "ARoT", + "version": "0.1.4", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } }, "value": { "digests": [ - "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" + "sha-256:o6XnFfDMV0pzw/m+u2vCTzL/1bZ7OHJEwskJ2neaFHg=" ] } } diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValOne.json b/scheme/psa-iot/test/corim/src/comid-bad-refval-mkey.json similarity index 75% rename from scheme/psa-iot/test/corim/src/ComidPsaRefValOne.json rename to scheme/psa-iot/test/corim/src/comid-bad-refval-mkey.json index 26536dd5..85fb3e07 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaRefValOne.json +++ b/scheme/psa-iot/test/corim/src/comid-bad-refval-mkey.json @@ -1,20 +1,8 @@ { - "lang": "en-GB", "tag-identity": { "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { @@ -23,9 +11,7 @@ "id": { "type": "psa.impl-id", "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + } } }, "measurements": [ @@ -43,6 +29,17 @@ "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" ] } + }, + { + "key": { + "type": "uint", + "value": 6 + }, + "value": { + "digests": [ + "sha-256:o6XnFfDMV0pzw/m+u2vCTzL/1bZ7OHJEwskJ2neaFHg=" + ] + } } ] } diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValMultDigest.json b/scheme/psa-iot/test/corim/src/comid-bad-refval-mval.json similarity index 54% rename from scheme/psa-iot/test/corim/src/ComidPsaRefValMultDigest.json rename to scheme/psa-iot/test/corim/src/comid-bad-refval-mval.json index 594d9fd6..09480ba6 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaRefValMultDigest.json +++ b/scheme/psa-iot/test/corim/src/comid-bad-refval-mval.json @@ -1,20 +1,8 @@ { - "lang": "en-GB", "tag-identity": { "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { @@ -23,9 +11,7 @@ "id": { "type": "psa.impl-id", "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + } } }, "measurements": [ @@ -33,20 +19,20 @@ "key": { "type": "psa.refval-id", "value": { - "label": "BL", - "version": "2.1.0", + "label": "ARoT", + "version": "0.1.4", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } }, "value": { - "digests": [ - "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", - "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJYjHl4Hu9eg/eYMTPJcc=" - ] + "svn": { + "type": "exact-value", + "value": 15208092991676743683 + } } } ] } ] } -} \ No newline at end of file +} diff --git a/scheme/psa-iot/test/corim/src/comid-bad-ta-cert.json b/scheme/psa-iot/test/corim/src/comid-bad-ta-cert.json new file mode 100644 index 00000000..34c50d6a --- /dev/null +++ b/scheme/psa-iot/test/corim/src/comid-bad-ta-cert.json @@ -0,0 +1,30 @@ +{ + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" + } + }, + "instance": { + "type": "ueid", + "value": "AUyj5PUL8kjDl4cCDWj/0FyIdndRvyZFypI/V6mL7NKW" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert", + "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKBadInst.json b/scheme/psa-iot/test/corim/src/comid-bad-ta-no-instance.json similarity index 56% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKBadInst.json rename to scheme/psa-iot/test/corim/src/comid-bad-ta-no-instance.json index 2e692f8b..4b4416dd 100644 --- a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKBadInst.json +++ b/scheme/psa-iot/test/corim/src/comid-bad-ta-no-instance.json @@ -1,25 +1,18 @@ { + "lang": "en-GB", "tag-identity": { - "id": "00000000-0000-0000-0000-000000000000" + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 }, - "entities": [ - { - "name": "EnactTrust", - "regid": "https://enacttrust.com", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "attester-verification-keys": [ { "environment": { - "instance": { - "type": "ueid", - "value": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "class": { + "id": { + "type": "psa.impl-id", + "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" + } } }, "verification-keys": [ diff --git a/scheme/arm-cca/test/corim/src/comidCcaRefValFour.json b/scheme/psa-iot/test/corim/src/comid-psa-refval.json similarity index 75% rename from scheme/arm-cca/test/corim/src/comidCcaRefValFour.json rename to scheme/psa-iot/test/corim/src/comid-psa-refval.json index 25b68c88..a862211f 100644 --- a/scheme/arm-cca/test/corim/src/comidCcaRefValFour.json +++ b/scheme/psa-iot/test/corim/src/comid-psa-refval.json @@ -4,17 +4,6 @@ "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B16", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "reference-values": [ { @@ -23,9 +12,7 @@ "id": { "type": "psa.impl-id", "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + } } }, "measurements": [ @@ -73,21 +60,9 @@ "sha-256:o6XnFfDMV0pzw/m+u2vCTzL/1bZ7OHJEwskJ2neaFHg=" ] } - }, - { - "key": { - "type": "cca.platform-config-id", - "value": "any-value" - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "cmF3dmFsdWUKcmF3dmFsdWUK" - } - } } ] } ] } -} \ No newline at end of file +} diff --git a/scheme/psa-iot/test/corim/src/ComidPsaIakPubTwo.json b/scheme/psa-iot/test/corim/src/comid-psa-ta.json similarity index 77% rename from scheme/psa-iot/test/corim/src/ComidPsaIakPubTwo.json rename to scheme/psa-iot/test/corim/src/comid-psa-ta.json index 47ef11d3..289ff488 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaIakPubTwo.json +++ b/scheme/psa-iot/test/corim/src/comid-psa-ta.json @@ -4,17 +4,6 @@ "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", "version": 0 }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], "triples": { "attester-verification-keys": [ { @@ -23,9 +12,7 @@ "id": { "type": "psa.impl-id", "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + } }, "instance": { "type": "ueid", @@ -35,7 +22,7 @@ "verification-keys": [ { "type": "pkix-base64-key", - "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----" } ] }, diff --git a/scheme/psa-iot/test/corim/src/corim-psa.json b/scheme/psa-iot/test/corim/src/corim-psa.json new file mode 100644 index 00000000..001f0e1e --- /dev/null +++ b/scheme/psa-iot/test/corim/src/corim-psa.json @@ -0,0 +1,4 @@ +{ + "corim-id": "00000000-0000-0000-065a-000000000000", + "profile": "http://arm.com/psa/iot/1" +} diff --git a/scheme/psa-iot/test/corim/src/corimMini.json b/scheme/psa-iot/test/corim/src/corimMini.json deleted file mode 100644 index f9528480..00000000 --- a/scheme/psa-iot/test/corim/src/corimMini.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", - "profile": "http://arm.com/psa/iot/1" -} diff --git a/scheme/psa-iot/test/corim/src/corims.yaml b/scheme/psa-iot/test/corim/src/corims.yaml new file mode 100644 index 00000000..f88c9abf --- /dev/null +++ b/scheme/psa-iot/test/corim/src/corims.yaml @@ -0,0 +1,21 @@ +corim: corim-psa +outdir: .. +workdir: ../__build +comids: + psa-valid: + - comid-psa-refval + - comid-psa-ta + psa-bad-class: + - comid-bad-class + psa-bad-instance: + - comid-bad-instance + psa-bad-ta-no-instance: + - comid-bad-ta-no-instance + psa-bad-refval-instance: + - comid-bad-refval-instance + psa-bad-ta-cert: + - comid-bad-ta-cert + psa-bad-refval-mkey: + - comid-bad-refval-mkey + psa-bad-refval-mval: + - comid-bad-refval-mval diff --git a/scheme/psa-iot/test/corim/submit-psa-iot-endorsements.sh b/scheme/psa-iot/test/corim/submit-psa-iot-endorsements.sh new file mode 100755 index 00000000..e7eba384 --- /dev/null +++ b/scheme/psa-iot/test/corim/submit-psa-iot-endorsements.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +cocli corim submit -i --corim-file corim-psa-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="http://arm.com/psa/iot/1"' --auth=none + diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoUeID.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoUeID.cbor deleted file mode 100644 index 5cc1c8c061ef14147c02baf5da5e8103e839c0b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 374 zcmcb~_;oQuKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9A8Euy^q^9QSx;rs0WC$?J<>HF$ zaDCg-p|2I)xkcXDkv=7k#V(fl2BzM@zGk^e>1lq>=>?@e2I*#D z1tA{UQ90(u<=LiAE*1G<=6Txwsi~<3nVyB&;l>`mQ6a{zA(?rZUMcCewp?H*xca%E eyNbC&0u&;k04d7VOU}>LFDOpb&&)5;Hv|9}^m>y3 diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor deleted file mode 100644 index 83fd80d558695ec8478174f5a6eec87270c1ebb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 413 zcmcb~_;oQuKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9A8B>-pq^9QSx;rs0WC$?J<>HF$ zaDCg-p|2I#94|7c12TGoO#+m#;S29inwzmFs~0o_l6*^hG%uZ!&3BY|sS( zCs%h*KZSr$Cm&B|1#j0#uppPOTXwl?d8CJTew1fbmVvWlV5BFM?cx}i>=Kyn=<1ed zP?DJMSRP~?kXz)P9qCizSnOh%Z(!;j>}!^rl%D42oL*4sV~}nZRuJNm9hGBlT%K*} z;g8j_ip>6MahYs&?8f~%hkx~rHgBtQWN3b&$M Sz2y8{{et2|{mlFleM10@$BD84 diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor deleted file mode 100644 index fd1d3698a81fa22d753450be39877c453a2f3954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 694 zcmcb~_;oQuKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9AnQE6Xq^9QSx;rs0WC$?J<>HF$ zaDCg-p|2I#94|7c12TGoO#+m#;S29inwzmFs~0o_l6*^hG%uZ!&3BY|sS( zCs%h*KZSr$Cm&B|1#j0#uppPOTXwl?d8CJTew1fbmVvWlV5BFM?cx}i>=Kyn=<1ed zP?DJMSRP~?kXz)P9qCizSnOh%Z(!;j>}!^rl%D42oL*4sV~}nZRuJNm9hGBlT%K*} z;g8j_ip>6MahYs&?8f~%hkx~r%VFg}Z)eC7V+ zad>(=6K}@<3o#vK<$?RvTu)814`12+=F&8(1dLf&d10z~My0X8MPxyuwo|BUh)-yi zlV7NDk!wU)Xl03Igh!CMhgZ0dyLm*2cVLQTreStiP(-RzfQye?URq>PsiA&qX+=<; rm#?{pWoW*ei%*Ipo`7MlkN~A9P=YGT)l1IL)h{Sc)X&T>(KiGD@}uUd diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaMultIak.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaMultIak.cbor deleted file mode 100644 index b1c7efd57fcf80628cbed370dded603b7dc1d6ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 594 zcmcb~_;oQuKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9AnIxAmq^9QSx;rs0WC$?J<>HF$ zaDCg-p|2I#94|7c12TGoO#+m#;S29inwzmFs~0o_l6*^hG(EZZc_AY|sS( zCs%h*KZSr$Cm&B|1#j0#uppPOTXwl?d8CJTew1fbmVvWlV5BFM?cx}i>=Kyn=<1ed zP?DJMSRP~?kXz)P9qCizSnOh%Z(!;j>}!^rl%D42oL*4sV~}nZRuJNm9hGBlT%K*} z;g8j_ip>6MahYs&?8f~%hkx~qnyqnRrtK(P&q V?4n$~2!low~)C8W%HUIy(EhD)^M7=rP_yO{Rzl1(39ECP*?jHLoPGBr`uxH#0@o016BlQ$VINWd-FYrUaGd z<)s!iE&}R|T+Eo{4< zpWfK@BAam`Q&SUTghIPh|52p|TSKT@<9?4Oi!rWrncP`$T`|6an8^Qy>06wLD$N&HU diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor deleted file mode 100644 index 8c0278f8b431c335e53eacce40c02409064e0572..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257 zcmV+c0sj8k0rjH*P+V8&^hV7>86c{q5fJ|k|3d&DR2`bIY zOD$?#$he5{CX)siQ)3fjgo4W|jmFUEj<2f_L=qD<2{-p)pYX~FS#kr bTp6c{q5fJ|k|3d&DR2`bIY zOD$?#1k@S1m@&!8hb7fW&rr{RH9}#{Zo%VEZYdVA2H8A0C#4egaFOLYo9w^yDhj_p zy|L>>HseC3#wNxHg?6X@qe>07hHP=w=WIUMKPlx*Gkp4>dT$l~y@Vs@RgW`QNPrv; Wa(7X#UUGh}enD}ferA4&z99hnL2oGl diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor deleted file mode 100644 index 54b3026a900ff0c7d538e846cf8ee47f9767cb44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 273 zcmcb~_;oQuKuq|HFK%a@q$i%_I6wKJ%^$|bn~c9AZZ2U+P0iDFcVb+~5a7J~alKxm zxAD5m!RJ3Zb&D}IE@sGdboO;s@F_{rW4xhIl2KApP;8~IpO~DRs+U@km|KvO%GAuj z$i%Xcp|NQp!(xV;Oc46c{q5fJ|k|3d&DR2`bIY zOD$?#1k@S1kTpVK&2GWtPi`p|u?E>ZIVYtO^>C5pI-Bgj^C}9zKfST*MKZIVYtO^>C5pI-Bgj^C}9z zKfST*MKS{QzW4aBBxii{62>Ga zAEpR}cBlTMN)5J#Y;o1+Y(CgODdkKveEOhzZx#Q&gd^uwkF%s2=^5%7utq4X*)4ed z$t}eq)*zcF=cH7k9xk$6XOsPRUPa;er#E)J$X>#j5)hOh0yL8;xoKwSw!c&Ti*~Ko zKjwYt(FfT~UEk-LZLb>o^JX^Mv!oj88S9x6XQm^>%*9Kei+(s0?p1vF=f2(9hy0EH zU)@%1QRH&yBG2SBE#!tM>y;|o|(gv8yNLje3!Gpzm-C(U91#X1bXgSWu?~MK*r)f5h_RZ6ajr)@R9%k literal 0 HcmV?d00001 diff --git a/scheme/psa-iot/test/token/psa.good.json b/scheme/psa-iot/test/token/psa.good.json new file mode 100644 index 00000000..c6403744 --- /dev/null +++ b/scheme/psa-iot/test/token/psa.good.json @@ -0,0 +1,31 @@ +{ + "eat-profile": "http://arm.com/psa/2.0.0", + "psa-client-id": 1, + "psa-security-lifecycle": 12288, + "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "psa-boot-seed": "3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+796tvu8=", + "psa-software-components": [ + { + "measurement-type": "BL", + "measurement-value": "h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", + "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", + "version": "2.1.0" + }, + { + "measurement-type": "PRoT", + "measurement-value": "AmOCmYm2/ZVPcrqvL8ZLwuLwHWktTecphuqAj26ZgT8=", + "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", + "version": "1.3.5" + }, + { + "measurement-type": "ARoT", + "measurement-value": "o6XnFfDMV0pzw/m+u2vCTzL/1bZ7OHJEwskJ2neaFHg=", + "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", + "version": "0.1.4" + + } + ], + "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", + "psa-verification-service-indicator": "https://psa-verifier.org", + "psa-nonce": "QUp8F0FBs9DpodKK8xUg8NQimf6sQAfe2J1ormzZLxk=" +} diff --git a/scheme/psa-iot/test/token/submit-psa-iot-evidence.sh b/scheme/psa-iot/test/token/submit-psa-iot-evidence.sh new file mode 100755 index 00000000..d65b7d4c --- /dev/null +++ b/scheme/psa-iot/test/token/submit-psa-iot-evidence.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession?nonce=QUp8F0FBs9DpodKK8xUg8NQimf6sQAfe2J1ormzZLxk= 2>/dev/null | grep "location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H "content-type: application/psa-attestation-token" --data-binary @psa.good.cose https://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/psa-iot/test_vars.go b/scheme/psa-iot/test_vars.go new file mode 100644 index 00000000..98329102 --- /dev/null +++ b/scheme/psa-iot/test_vars.go @@ -0,0 +1,33 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package psa_iot + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-psa-bad-class.cbor + corimPsaBadClass []byte + + //go:embed test/corim/corim-psa-bad-instance.cbor + corimPsaBadInstance []byte + + //go:embed test/corim/corim-psa-bad-refval-instance.cbor + corimPsaBadRefvalInstance []byte + + //go:embed test/corim/corim-psa-bad-refval-mkey.cbor + corimPsaBadRefvalMkey []byte + + //go:embed test/corim/corim-psa-bad-refval-mval.cbor + corimPsaBadRefvalMval []byte + + //go:embed test/corim/corim-psa-bad-ta-cert.cbor + corimPsaBadTaCert []byte + + //go:embed test/corim/corim-psa-bad-ta-no-instance.cbor + corimPsaBadTaNoInstance []byte + + //go:embed test/corim/corim-psa-valid.cbor + corimPsaValid []byte +) diff --git a/scheme/psa-iot/test_vectors.go b/scheme/psa-iot/test_vectors.go deleted file mode 100644 index 565bb89e..00000000 --- a/scheme/psa-iot/test_vectors.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package psa_iot - -import _ "embed" - -var ( - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor - unsignedCorimComidPsaIakPubOne []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor - unsignedCorimComidPsaIakPubTwo []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaRefValOne.cbor - unsignedCorimComidPsaRefValOne []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaRefValThree.cbor - unsignedCorimComidPsaRefValThree []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaMultIak.cbor - unsignedCorimComidPsaMultIak []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaRefValMultDigest.cbor - unsignedCorimComidPsaRefValMultDigest []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor - unsignedCorimComidPsaRefValOnlyMandIDAttr []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaRefValNoMkey.cbor - unsignedCorimComidPsaRefValNoMkey []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor - unsignedCorimComidPsaRefValNoImplID []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaIakPubNoUeID.cbor - unsignedCorimComidPsaIakPubNoUeID []byte - - // nolint:unused - //go:embed test/corim/unsignedCorimMiniComidPsaIakPubNoImplID.cbor - unsignedCorimComidPsaIakPubNoImplID []byte -) diff --git a/scheme/riot/Makefile b/scheme/riot/Makefile index 3fd7c3ea..e0b17a5a 100644 --- a/scheme/riot/Makefile +++ b/scheme/riot/Makefile @@ -1,4 +1,4 @@ -# Copyright 2021 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 .DEFAULT_GOAL := test diff --git a/scheme/riot/corim.go b/scheme/riot/corim.go new file mode 100644 index 00000000..f0bf3022 --- /dev/null +++ b/scheme/riot/corim.go @@ -0,0 +1,64 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package riot + +import ( + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/services/scheme/common" +) + +const ProfileString = "tag:veraison-project.com,2026:riot" + +func validateEnvironment(env *comid.Environment) error { + if env.Class.Vendor == nil { + return errors.New("missing vendor") + } + + if *env.Class.Vendor != "Veraison Project" { + return errors.New(`vendor must be "Veraison Project"`) + } + + if env.Class.Model == nil { + return errors.New("missing vendor") + } + + if *env.Class.Model != "RIOT" { + return errors.New(`vendor must be "RIOT"`) + } + + return nil +} + +func validateCryptoKeys(keys []*comid.CryptoKey) error { + for _, key := range keys { + if key.Type() != comid.PKIXBase64CertPathType && key.Type() != comid.PKIXBase64CertType { + return fmt.Errorf("key must be a cert or a cert path, found: %s", key.Type()) + } + } + + return nil +} + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + validator := &common.TriplesValidator{ + EnviromentValidator: validateEnvironment, + CryptoKeysValidator: validateCryptoKeys, + DisallowRefVals: true, + } + + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/riot/corim_test.go b/scheme/riot/corim_test.go new file mode 100644 index 00000000..c5274877 --- /dev/null +++ b/scheme/riot/corim_test.go @@ -0,0 +1,40 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package riot + +import ( + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "ok", + Input: corimRiotValid, + }, + { + Title: "bad ref. vals. present", + Input: corimRiotBadRefvals, + Err: "found reference values", + }, + { + Title: "bad no vendor", + Input: corimRiotBadNoVendor, + Err: "missing vendor", + }, + { + Title: "bad wrong vendor", + Input: corimRiotBadWrongVendor, + Err: `vendor must be "Veraison Project"`, + }, + { + Title: "bad wrong key type", + Input: corimRiotBadWrongKeyType, + Err: `key must be a cert`, + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/riot/evidence_handler.go b/scheme/riot/evidence_handler.go deleted file mode 100644 index 18de7415..00000000 --- a/scheme/riot/evidence_handler.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package riot - -import ( - "crypto/x509" - "encoding/asn1" - "encoding/pem" - "errors" - - "github.com/veraison/dice" - "github.com/veraison/ear" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -var altNameID = asn1.ObjectIdentifier{2, 5, 29, 17} - -type EvidenceHandler struct { -} - -func (s EvidenceHandler) GetName() string { - return "riot-evidence-handler" -} - -func (s EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func (s EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - roots := x509.NewCertPool() - intermediates := x509.NewCertPool() - - if err := parseTrustAnchor([]byte(trustAnchors[0]), roots, intermediates); err != nil { - return nil, err - } - - aliasCert, err := parseTokenCerts(token.Data, intermediates, roots) - if err != nil { - return nil, handler.BadEvidence(err) - } - - opts := x509.VerifyOptions{ - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, - Roots: roots, - Intermediates: intermediates, - } - - claims, err := extractEvidenceClaims(aliasCert) - if err != nil { - return nil, handler.BadEvidence(err) - } - - // note: must verify this after extracting claims so that the Subject Alternative Name - // gets processed; otherwise, it will be raised an unhandled critical extension. - if _, err = aliasCert.Verify(opts); err != nil { - return nil, handler.BadEvidence( - "failed to verify alias cert: " + err.Error()) - } - - return claims, nil -} - -func (s EvidenceHandler) ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - endorsements []string, -) error { - // Cert verified earlier when extracting claims -- see note inside ExtractClaims above. - return nil -} - -func (s EvidenceHandler) AppraiseEvidence( - ec *proto.EvidenceContext, - endorsementsString []string, -) (*ear.AttestationResult, error) { - result := handler.CreateAttestationResult(SchemeName) - - // If we got this far, this means the cert chain has been verfied, and - // thus, the identity has been established as valid. - result.Submods[SchemeName].TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim - - return result, nil -} - -func extractEvidenceClaims(cert *x509.Certificate) (map[string]interface{}, error) { - claims := make(map[string]interface{}) - - for _, ext := range cert.Extensions { - if ext.Id.Equal(altNameID) { - if err := processAltName(ext.Value, &claims); err != nil { - return nil, err - } - break - } - } - - // Remove Subject Alternative Name from Unhandled critical extensions list, as - // we've now "handled" it. This will allow the cert to be verified. - altNameIdx := -1 - for i, extOID := range cert.UnhandledCriticalExtensions { - if extOID.Equal(altNameID) { - altNameIdx = i - break - } - } - - if altNameIdx != -1 { - cert.UnhandledCriticalExtensions = append(cert.UnhandledCriticalExtensions[:altNameIdx], - cert.UnhandledCriticalExtensions[altNameIdx+1:]...) - } - - return claims, nil -} - -func processAltName(data []byte, claims *map[string]interface{}) error { - - var dice dice.DiceExtension - - rest, err := dice.UnmarshalDER(data) - if err != nil { - return err - } - if len(rest) != 0 { - return errors.New("trailing data after DICE extension") - } - - (*claims)["FWID"] = dice.CompositeDeviceID.Fwid.Fwid - (*claims)["DeviceID"] = dice.CompositeDeviceID.DeviceID.SubjectPublicKey.Bytes - - return nil -} - -func parseTokenCerts(token []byte, intermediates *x509.CertPool, roots *x509.CertPool) (*x509.Certificate, error) { - block, rest := pem.Decode(token) - if block == nil { - return nil, errors.New("problem extracting token cert PEM block") - } - - aliasCert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, err - } - - block, rest = pem.Decode(rest) - if block == nil { - return nil, errors.New("problem extracting token cert PEM block") - } - - deviceCert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, err - } - - // self signed cert should not have any intermediates presented with it. - if deviceCert.Subject.String() == deviceCert.Issuer.String() { - if len(rest) != 0 { - return nil, errors.New("additional data found alongside a self-signed Cert") - } - - roots.AddCert(deviceCert) - - return aliasCert, nil - } - - // Device cert is not self-signed. Add it as an intermediate and process - // the rest of the certs if any. - - intermediates.AddCert(deviceCert) - - for len(rest) != 0 { - block, rest = pem.Decode(rest) - if block == nil { - return nil, errors.New("problem extracting token intermediate PEM block") - } - - intCert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, err - } - - intermediates.AddCert(intCert) - } - - return aliasCert, nil -} - -func parseTrustAnchor(trustAnchor []byte, roots *x509.CertPool, intermediates *x509.CertPool) error { - var block *pem.Block - rest := trustAnchor - for len(rest) != 0 { - block, rest = pem.Decode(rest) - if block == nil { - return errors.New("problem extracting trust anchor PEM block") - } - - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return err - } - - if cert.Subject.String() == cert.Issuer.String() { - // self-signed - roots.AddCert(cert) - } else { - intermediates.AddCert(cert) - } - } - - return nil -} diff --git a/scheme/riot/evidence_handler_test.go b/scheme/riot/evidence_handler_test.go deleted file mode 100644 index 3bb1b2f2..00000000 --- a/scheme/riot/evidence_handler_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package riot - -import ( - "os" - "testing" - - "github.com/veraison/services/proto" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var FWID = []uint8{ - 0x6e, 0x34, 0x0b, 0x9c, 0xff, 0xb3, 0x7a, 0x98, 0x9c, 0xa5, 0x44, - 0xe6, 0xbb, 0x78, 0x0a, 0x2c, 0x78, 0x90, 0x1d, 0x3f, 0xb3, 0x37, - 0x38, 0x76, 0x85, 0x11, 0xa3, 0x06, 0x17, 0xaf, 0xa0, 0x1d, -} - -var DeviceID = []uint8{ - 0x04, 0x9f, 0x34, 0x66, 0x25, 0x8b, 0x71, 0x06, 0x23, 0x7f, 0xeb, - 0x64, 0x8d, 0xdf, 0xd5, 0x56, 0xb8, 0xb9, 0x38, 0xc3, 0x07, 0x6a, - 0x61, 0x89, 0x40, 0x97, 0x5f, 0x20, 0x98, 0x9d, 0x61, 0xf3, 0x79, - 0x9d, 0x04, 0x82, 0xf4, 0x6c, 0x8c, 0x4a, 0x94, 0xba, 0x5e, 0x00, - 0x3d, 0xda, 0x66, 0x8f, 0x58, 0xc2, 0x90, 0xca, 0x6f, 0x63, 0xda, - 0xe5, 0xcd, 0x5a, 0x5a, 0x54, 0xcc, 0x0c, 0x07, 0x2f, 0xae, -} - -func Test_ExtractVerifiedClaims_ok(t *testing.T) { - deviceData, err := os.ReadFile("test/DeviceCerts.pem") - require.NoError(t, err, "could not read device certs file") - - taData, err := os.ReadFile("test/TrustAnchor.pem") - require.NoError(t, err, "could not read trust anchor file") - - s := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "1", - Data: deviceData, - } - ta := string(taData) - claims, err := s.ExtractClaims(&token, []string{ta}) - assert.Nil(t, err) - assert.Equal(t, FWID, claims["FWID"]) - assert.Equal(t, DeviceID, claims["DeviceID"]) -} diff --git a/scheme/riot/plugin/Makefile b/scheme/riot/plugin/Makefile index 8375f5bb..fe0ea0f6 100644 --- a/scheme/riot/plugin/Makefile +++ b/scheme/riot/plugin/Makefile @@ -1,10 +1,11 @@ +# Copyright 2023-2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-riot.plugin +GOPKG := github.com/veraison/services/scheme/riot +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/riot/plugin/combined/Makefile b/scheme/riot/plugin/combined/Makefile deleted file mode 100644 index d3387928..00000000 --- a/scheme/riot/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2021 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/riot.plugin -GOPKG := github.com/veraison/services/scheme/riot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/riot/plugin/combined/main.go b/scheme/riot/plugin/combined/main.go deleted file mode 100644 index d637ed3e..00000000 --- a/scheme/riot/plugin/combined/main.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/riot" -) - -func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/riot/plugin/evidence-handler/Makefile b/scheme/riot/plugin/evidence-handler/Makefile deleted file mode 100644 index a52293f0..00000000 --- a/scheme/riot/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2021 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/tcg-dice-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/riot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/riot/plugin/evidence-handler/main.go b/scheme/riot/plugin/main.go similarity index 60% rename from scheme/riot/plugin/evidence-handler/main.go rename to scheme/riot/plugin/main.go index 3c5944ce..905ad313 100644 --- a/scheme/riot/plugin/evidence-handler/main.go +++ b/scheme/riot/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) plugin.Serve() } diff --git a/scheme/riot/plugin/store-handler/Makefile b/scheme/riot/plugin/store-handler/Makefile deleted file mode 100644 index cbaf5abe..00000000 --- a/scheme/riot/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/riot.plugin -GOPKG := github.com/veraison/services/scheme/riot -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/riot/plugin/store-handler/main.go b/scheme/riot/plugin/store-handler/main.go deleted file mode 100644 index 905f3ea4..00000000 --- a/scheme/riot/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/riot" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/riot/scheme.go b/scheme/riot/scheme.go index 31c961f6..764f6d6f 100644 --- a/scheme/riot/scheme.go +++ b/scheme/riot/scheme.go @@ -1,9 +1,266 @@ -// Copyright 2023 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package riot -const SchemeName = "riot" +import ( + "crypto/x509" + "encoding/asn1" + "encoding/pem" + "errors" + "fmt" -var EvidenceMediaTypes = []string{ - "application/pem-certificate-chain", + "github.com/veraison/corim/comid" + "github.com/veraison/dice" + "github.com/veraison/ear" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" +) + +var altNameID = asn1.ObjectIdentifier{2, 5, 29, 17} + +var Descriptor = handler.SchemeDescriptor{ + Name: "RIOT", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + }, + EvidenceMediaTypes: []string{ + "application/pem-certificate-chain", + }, +} + +type Implementation struct { + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), + } +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + vendor := "Veraison Project" + model := "RIOT" + + return []*comid.Environment{ + { + Class: &comid.Class{ + Vendor: &vendor, + Model: &model, + }, + }, + }, nil +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + roots := x509.NewCertPool() + intermediates := x509.NewCertPool() + + if err := parseTrustAnchors(trustAnchors, roots, intermediates); err != nil { + return nil, err + } + + aliasCert, err := parseEvidenceCerts(evidence.Data, intermediates, roots) + if err != nil { + return nil, handler.BadEvidence(err) + } + + opts := x509.VerifyOptions{ + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + Roots: roots, + Intermediates: intermediates, + } + + claims, err := extractEvidenceClaims(aliasCert) + if err != nil { + return nil, handler.BadEvidence(err) + } + + // note: must verify this after extracting claims so that the Subject Alternative Name + // gets processed; otherwise, it will be raised an unhandled critical extension. + if _, err = aliasCert.Verify(opts); err != nil { + return nil, handler.BadEvidence( + "failed to verify alias cert: " + err.Error()) + } + + return claims, nil +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + // Cert verified earlier when extracting claims -- see note inside ExtractClaims above. + return nil +} + +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + appraisal := result.Submods[Descriptor.Name] + + // If we got this far, this means the cert chain has been verfied, and + // thus, the identity has been established as valid. + appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim + + appraisal.UpdateStatusFromTrustVector() + appraisal.VeraisonPolicyClaims = &claims + + return result, nil +} + +func extractEvidenceClaims(cert *x509.Certificate) (map[string]any, error) { + claims := make(map[string]any) + + for _, ext := range cert.Extensions { + if ext.Id.Equal(altNameID) { + if err := processAltName(ext.Value, &claims); err != nil { + return nil, err + } + break + } + } + + // Remove Subject Alternative Name from Unhandled critical extensions list, as + // we've now "handled" it. This will allow the cert to be verified. + altNameIdx := -1 + for i, extOID := range cert.UnhandledCriticalExtensions { + if extOID.Equal(altNameID) { + altNameIdx = i + break + } + } + + if altNameIdx != -1 { + cert.UnhandledCriticalExtensions = append(cert.UnhandledCriticalExtensions[:altNameIdx], + cert.UnhandledCriticalExtensions[altNameIdx+1:]...) + } + + return claims, nil +} + +func processAltName(data []byte, claims *map[string]any) error { + + var dice dice.DiceExtension + + rest, err := dice.UnmarshalDER(data) + if err != nil { + return err + } + if len(rest) != 0 { + return errors.New("trailing data after DICE extension") + } + + (*claims)["FWID"] = dice.CompositeDeviceID.Fwid.Fwid + (*claims)["DeviceID"] = dice.CompositeDeviceID.DeviceID.SubjectPublicKey.Bytes + + return nil +} + +func parseEvidenceCerts( + evidence []byte, + intermediates *x509.CertPool, + roots *x509.CertPool, +) (*x509.Certificate, error) { + block, rest := pem.Decode(evidence) + if block == nil { + return nil, errors.New("problem extracting token cert PEM block") + } + + aliasCert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + + block, rest = pem.Decode(rest) + if block == nil { + return nil, errors.New("problem extracting token cert PEM block") + } + + deviceCert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + + // self signed cert should not have any intermediates presented with it. + if deviceCert.Subject.String() == deviceCert.Issuer.String() { + if len(rest) != 0 { + return nil, errors.New("additional data found alongside a self-signed Cert") + } + + roots.AddCert(deviceCert) + + return aliasCert, nil + } + + // Device cert is not self-signed. Add it as an intermediate and process + // the rest of the certs if any. + + intermediates.AddCert(deviceCert) + + for len(rest) != 0 { + block, rest = pem.Decode(rest) + if block == nil { + return nil, errors.New("problem extracting token intermediate PEM block") + } + + intCert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + + intermediates.AddCert(intCert) + } + + return aliasCert, nil +} + +func parseTrustAnchors( + trustAnchors []*comid.KeyTriple, + roots *x509.CertPool, + intermediates *x509.CertPool, +) error { + for _, keyTriple := range trustAnchors { + for _, verifKey := range keyTriple.VerifKeys { + switch verifKey.Type() { + case comid.PKIXBase64CertType, comid.PKIXBase64CertPathType: + var block *pem.Block + rest := []byte(verifKey.Value.String()) + for len(rest) != 0 { + block, rest = pem.Decode(rest) + if block == nil { + return errors.New("problem extracting trust anchor PEM block") + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return err + } + + if cert.Subject.String() == cert.Issuer.String() { + // self-signed + roots.AddCert(cert) + } else { + intermediates.AddCert(cert) + } + } + default: + return fmt.Errorf("unexpected verif. key type: %s", verifKey.Type()) + } + } + } + + return nil } diff --git a/scheme/riot/store_handler.go b/scheme/riot/store_handler.go deleted file mode 100644 index ed293354..00000000 --- a/scheme/riot/store_handler.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2021-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package riot - -import ( - "errors" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -type StoreHandler struct { -} - -func (s StoreHandler) GetName() string { - return "riot-store-handler" -} - -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - return []string{"dice://"}, nil -} - -func (s StoreHandler) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - return []string{"dice://"}, nil -} - -func (s StoreHandler) SynthKeysFromRefValue(tenantID string, swComp *handler.Endorsement) ([]string, error) { - return nil, errors.New("TODO") -} - -func (s StoreHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) { - return nil, errors.New("TODO") -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - return []string{"TODO"}, nil -} diff --git a/scheme/riot/test/corim/compile-endorsements.sh b/scheme/riot/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..48308891 --- /dev/null +++ b/scheme/riot/test/corim/compile-endorsements.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p riot "$THIS_DIR"/corim-*.cbor diff --git a/scheme/riot/test/TrustAnchor.pem b/scheme/riot/test/corim/corim-riot-bad-no-vendor.cbor similarity index 91% rename from scheme/riot/test/TrustAnchor.pem rename to scheme/riot/test/corim/corim-riot-bad-no-vendor.cbor index 068ea6bb4568cea3468453ec9b8591d2ced4edd5..c1da12954241d93107ebbf34640084faaa792361 100644 GIT binary patch delta 297 zcmZ3&*Ulezlkw|fh6+^!D9{Db5W>XJz#Pni$r&>?-emk0$*#AEaUnwh12S-AXJlE( z+}N~`VIfmWkf(o0<4q==N_LhB(i3GIC&oEWT;MqIks~A52$hWTVzIGH$>c-q2E`2kc3F~xE6K32y`Y>tzi*g)1>v&cZ?fQDSCsex7bYQGQlxa*1AYey)y@fsvV2QD%M#08^n>f&c&j delta 280 zcmZqYU&1#rPMVQ-Vx=RH*aaef1BuBtj3BZWOzs1d|G}gK6G*&~$xxP;OBV!O{ah5B zU4ueA-8`KgLtMdPyj);2C%*tIZeRszImjwKS&xx#@?>TSAa6A@NbC)m)MWv&^T6bK zF!_N+k{ILd!3M*OcVyw^3J9Hij9G26HXFzeXEuz`BGjUFS%O(jF KWMg;4Zvg-aP(rW( diff --git a/scheme/riot/test/corim/corim-riot-bad-refvals.cbor b/scheme/riot/test/corim/corim-riot-bad-refvals.cbor new file mode 100644 index 0000000000000000000000000000000000000000..8e41cd9c354bd0953d35af2c3b1616a6e5b46d7c GIT binary patch literal 2049 zcmd7T%a7Yc90%~twxYrp{)JVgp4ugL9@|X?LNoR_o+Oj_?ZgL!U+XxI?X2TR>|WSj zIPy1ad*Pqp2I25=6`-fpvf!!ZpPuml}0{rbtz z`TJ+gFF!r~y8htD&%XKL!FP9d_j%q}>0W9D>m)uB(`4Z}*`X`riF$E$_^7&f_juPJ z>f`Ydi)0n^m<1}@S1E!qOgNSWn&E>IL*Qc`NSK2_D_MVrhlz>n1&y|SrBtIifv0`I zXxr;@rbl{Cnf+dc(K2`YdSx4WXc;_hDv*;DP!SoGTsh-(Ng8rsKGvAQnT~W-=g^3N za6b?Q=Y-XDQVMftOcr26IK17$lBl3%>}vI{hPv0a1>}f=O5x?e9L2%8VH(}gZew3D zy0keRWTqjnW>a~I(HLS5ZIB8?=#O;>62c-z)s{U?*2fx=)+NPC`ziKOIncElngo(Q ztj_xi>GXh)`YikEyhH+^F@OWt;6!m$Ht8UbS(hq@8V5R^)TaemN>&Ke>tYUETg`%c z6fMvap_N_U&k ziPp_kFzlL$Cxy|r2WNOZU?`@Xw^2`A2Rc4J-UkR=265Ze_(4L)q!kHec5yW>edWyfRzO1tk{!5@$_kVF_bvt0hf`6X%3k ziGjeI6=$k(8>N+nn-WOe(9$|)Zkf06SZ&hhKRWWs1Jw|{% z_s+Y`!j76@D3qbJlI=~%c)|AfOue96J4Hv7us;90!-zVWmaA!ew_+2}MfOZl=<0 zd~VZ2!HFwI9bpi;{nc<|b*Hll7lxTq)49AXkM&;DY$yd~(CP=8IOn|!WAN$2B4Dwt)bs~Az?5yF(K zS;*Yjw2)yD zV?kJIQDSCsex5==QGQlxatTvPkf(o0<4q>5iVeCT;N8B77>g40;tl;e$2^Qq? zb;~YyEsyl@&X4k}$}(_v42<-IvRxbllU)MS9bL11(h^I|yfV|YGpn3k)AhZbDw6%o zvfWIJQ@si!4D(zwT|7#hGpfRj%e*{1(+kT@oQpzA^MV4jb21$>U5ta$EsK0|bHkD< zL$deL3b5%g;Ggkx>Xs}OS%ORFX<)c=js?47@1iWW#*Rv E0FTCC1^@s6 literal 0 HcmV?d00001 diff --git a/scheme/riot/test/corim/corim-riot-bad-wrong-vendor.cbor b/scheme/riot/test/corim/corim-riot-bad-wrong-vendor.cbor new file mode 100644 index 0000000000000000000000000000000000000000..202233445be64e80a2cca4a4416fde9b933898aa GIT binary patch literal 1933 zcmd7S&u*he90%}Zccn-?#i~+I*{#9G*?6TMW?+D^JvPJNn419yV~nveFos+DCfPn! z9;BC^YI`@?rm53Py>ujC`2D2O03W^&=fC}Ww)>I)Ha;G%Ur(aIe>%<{d*b=s!};%% z3-QbO{h5CD=K(Ix-`&5x`{n-Z%XtVSg5HD%9$R-0Z$8u)?>-&|L@FM=myls$1xvs} z$0|oKhM6o$z;+|RFa!}+0L3x{Hj|=g7WC0yUBL{+vNJy~kWzRO8kxl59aS}alQAMop*bVduBr2>os!7Bih>$8t-{uTy zfX4v#Ls!=IA#3q*xspPT4Qv^RVjl6DL9;ai&9<6@(6@@X8Kz4s-}=gst(qaw%xOcr z$s}EM{Bj0&v+@%3G%gI>jx==_{RKz}#D^CXB8Fg#QB1%Dg4=5eP{QPBzf*(P0o7U% zPOoE+lE~-3tIPp0(I9`rV#wtOLdp^AIXik@WkTvfDJWgk?nxa;~80@7x->9#6AZ6%4u61q10T_Vil z{qLF2;%*aEqE2yiqnUIxY*lW#b7SX9m&%2}Rf=a6HXu$s=qv?iIKPG>DDcn!fz|CH z#Z2{o$7-KmCT18MGe(x-@+qwBv{!}FAu6HH>GtzfI>qOd9uAH}Jr%Wn8mjBTZrZ(> zjO8RL%!V&r(ev)KZ)#i;h!Xrbw?42;`JkIj1F#sOaI-Gr@Q(erlqLotm$SF?N?Z?o0M Wb)GF|LGe?Nr61aS`|5KZXT=|hAyN+j literal 0 HcmV?d00001 diff --git a/scheme/riot/test/corim/corim-riot-valid.cbor b/scheme/riot/test/corim/corim-riot-valid.cbor new file mode 100644 index 0000000000000000000000000000000000000000..5f74f760aee1682e9b6f477f1ca2e613240118c4 GIT binary patch literal 1945 zcmd7T+is&q7zglVccn-?#cHKqWmAI>*?6T&oq++y_Sg)^m^%Xw#u#H`U<`NZn`HY` zd63@ps?hhf`bNzZ`l`W5Vg}{ps)H zv!B16-koSCe{SIH^uyiz+h6WZzMZb@X*P*A>GGqNrSqwuzYBCcGH>tSeXhm?r!KDNJlc&hTB8|(R|*iU z-8~!IiCu86(ycIB6oFz_o@2)oN9J7vO4I-q(Gio_Sh6YYOJFv%gx-yfY}1y|fPnZg z5eH{Pv~9xFnLi|Ruq6`S9Wf&&Xgd2^y|1Cpb8QYKVj!kIOe}E{oH?%3iMk8-kRGNHDEM*V65wMd*fcB0VfoL9Az6HFOCi3ar+O zLE2pqB1IG*`wXdo#{l*MN7A$bYw%IA6a$X+EeW*SS;(t8O;-rin{oyM&&;EGkSxq> z4Nv<{%~z?_W%S7=jH(F#%%;ZmvW? z36sLzN_AcXRBb>&rQO#;1f&Z0v_uGq2>2KfG!`)x2kXvMBO1D{H%*8uJ7_>Z*)&#B zzvCjAlupa*-QZzQ-~@(eKm+rIrG(uI+U`P6sG44RYLVaA&3L5Ay4j&q5wTMNM+ z%&uS?@f=oG(k%mVAC*w!H0xz59piIM4+lqq zmbBGg5-6+wcG9^XkEA%xjhZim03IReYKKTu1t%11f(L$imgmJA{2#b zHgmmu*<4x>%1-6ii_t4SFZEc@dbq!)(n~(ip=8U;l$OGx-7%b`oDw3i)na5wJ{Km& zm2hdnZL^A!qF>DDK9m-`RaKrm&WDxDhI3VGq+ryHyKLGG)|M&gX|FuL?!;{MhMxD^ ePx&PLT0ZWR7psST@<%^SJ~#R1<<~4q^FIJz1y@V} literal 0 HcmV?d00001 diff --git a/scheme/riot/test/corim/src/comid-bad-no-vendor.json b/scheme/riot/test/corim/src/comid-bad-no-vendor.json new file mode 100644 index 00000000..4278b1cc --- /dev/null +++ b/scheme/riot/test/corim/src/comid-bad-no-vendor.json @@ -0,0 +1,22 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000000410701" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "model": "RIOT" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert-path", + "value": "-----BEGIN CERTIFICATE-----\nMIIBoDCCAUWgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwQzEhMB8GA1UEAwwYVmVu\nZG9yIEludGVybWVkaWF0ZSBDQSAyMREwDwYDVQQKDAhNU1JfVEVTVDELMAkGA1UE\nBhMCVVMwHhcNMjAxMDIxMDkwMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQD\nDBhWZW5kb3IgSW50ZXJtZWRpYXRlIENBIDExETAPBgNVBAoMCE1TUl9URVNUMQsw\nCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJdWDPPLw/0iunCd\nwKUDA44rg0HRQopEAzsvhAdbTtizLmlTrsbFLwnzLAHSazQ5kYmn3bueBxeu+A9H\ndcW3CaWjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgIEMAoG\nCCqGSM49BAMCA0kAMEYCIQCLq5ePMPEXzs2BIyVd/Bcms/piK5ZEFMvW3bJfINJ1\n1wIhAPAjlUGg9yBVZlRmQHo8bHutfV2kOPFRT5QeCB3sr4G0\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBjTCCATOgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQDDBhWZW5kb3IgSW50ZXJtZWRp\nYXRlIENBIDIxETAPBgNVBAoMCE1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABDvKRc90bFzzMnCrbamewtphHSnPgwIt/cjaHNaH\ndrrKOc61pPiHFZyDZTn3EryaI/QAodkaU4ZuaZBZqAyTb1mjJjAkMBIGA1UdEwEB\n/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgIEMAoGCCqGSM49BAMCA0gAMEUCIQCn\n8y7EACqeq5/vbm/kkHwkQpRbxk1eiBDMrei5zcv4PQIgXHSQNL/vWuxWiV6PCuj1\nvFZRtUAMViK3l1VLh8B4AtI=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBfDCCASGgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjAxMSIwIAYDVQQDDBlWZW5kb3IgUm9vdCBDQSBP\nPU1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBOdPm4HJmdGpKxa5XYODkktSz0uW4ZZI+u1hAQivr4dccHyFpZFQuzOADuiruxFQ\nM1uuTT2tR962nUBBFWyczlOjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQUwDgYDVR0P\nAQH/BAQDAgIEMAoGCCqGSM49BAMCA0kAMEYCIQCVFnoQv1l45SWmveMM1wplOSDc\ngmS816UBx2yimuKuhQIhAPl0UyybFYtNyZwNjHP/oAO2k9we9dqUT1RoJv+X5kwp\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/riot/test/corim/src/comid-bad-refvals.json b/scheme/riot/test/corim/src/comid-bad-refvals.json new file mode 100644 index 00000000..dac9e6a5 --- /dev/null +++ b/scheme/riot/test/corim/src/comid-bad-refvals.json @@ -0,0 +1,46 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000000410701" + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" + }, + "vendor": "ACME", + "model": "RoadRunner" + } + }, + "measurements": [ + { + "value": { + "digests": [ + "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" + ] + } + } + ] + } + ], + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "Veraison Project", + "model": "RIOT" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert-path", + "value": "-----BEGIN CERTIFICATE-----\nMIIBoDCCAUWgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwQzEhMB8GA1UEAwwYVmVu\nZG9yIEludGVybWVkaWF0ZSBDQSAyMREwDwYDVQQKDAhNU1JfVEVTVDELMAkGA1UE\nBhMCVVMwHhcNMjAxMDIxMDkwMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQD\nDBhWZW5kb3IgSW50ZXJtZWRpYXRlIENBIDExETAPBgNVBAoMCE1TUl9URVNUMQsw\nCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJdWDPPLw/0iunCd\nwKUDA44rg0HRQopEAzsvhAdbTtizLmlTrsbFLwnzLAHSazQ5kYmn3bueBxeu+A9H\ndcW3CaWjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgIEMAoG\nCCqGSM49BAMCA0kAMEYCIQCLq5ePMPEXzs2BIyVd/Bcms/piK5ZEFMvW3bJfINJ1\n1wIhAPAjlUGg9yBVZlRmQHo8bHutfV2kOPFRT5QeCB3sr4G0\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBjTCCATOgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQDDBhWZW5kb3IgSW50ZXJtZWRp\nYXRlIENBIDIxETAPBgNVBAoMCE1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABDvKRc90bFzzMnCrbamewtphHSnPgwIt/cjaHNaH\ndrrKOc61pPiHFZyDZTn3EryaI/QAodkaU4ZuaZBZqAyTb1mjJjAkMBIGA1UdEwEB\n/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgIEMAoGCCqGSM49BAMCA0gAMEUCIQCn\n8y7EACqeq5/vbm/kkHwkQpRbxk1eiBDMrei5zcv4PQIgXHSQNL/vWuxWiV6PCuj1\nvFZRtUAMViK3l1VLh8B4AtI=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBfDCCASGgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjAxMSIwIAYDVQQDDBlWZW5kb3IgUm9vdCBDQSBP\nPU1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBOdPm4HJmdGpKxa5XYODkktSz0uW4ZZI+u1hAQivr4dccHyFpZFQuzOADuiruxFQ\nM1uuTT2tR962nUBBFWyczlOjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQUwDgYDVR0P\nAQH/BAQDAgIEMAoGCCqGSM49BAMCA0kAMEYCIQCVFnoQv1l45SWmveMM1wplOSDc\ngmS816UBx2yimuKuhQIhAPl0UyybFYtNyZwNjHP/oAO2k9we9dqUT1RoJv+X5kwp\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/riot/test/corim/src/comid-bad-wrong-key-type.json b/scheme/riot/test/corim/src/comid-bad-wrong-key-type.json new file mode 100644 index 00000000..9a04a2aa --- /dev/null +++ b/scheme/riot/test/corim/src/comid-bad-wrong-key-type.json @@ -0,0 +1,23 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000000410701" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "Veraison Project", + "model": "RIOT" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkLfat6Jif+izCEg/KBxcN6kF5seJqX1nEiDHtChzV3vJHIgqw4CrTunRP+liAiD3Rg9rLmmVbyUjPKXlwBdHxA==\n-----END PUBLIC KEY-----" + } + ] + } + ] + } +} diff --git a/scheme/riot/test/corim/src/comid-bad-wrong-vendor.json b/scheme/riot/test/corim/src/comid-bad-wrong-vendor.json new file mode 100644 index 00000000..6f865ba3 --- /dev/null +++ b/scheme/riot/test/corim/src/comid-bad-wrong-vendor.json @@ -0,0 +1,23 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000000410701" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "ACME", + "model": "RIOT" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert-path", + "value": "-----BEGIN CERTIFICATE-----\nMIIBoDCCAUWgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwQzEhMB8GA1UEAwwYVmVu\nZG9yIEludGVybWVkaWF0ZSBDQSAyMREwDwYDVQQKDAhNU1JfVEVTVDELMAkGA1UE\nBhMCVVMwHhcNMjAxMDIxMDkwMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQD\nDBhWZW5kb3IgSW50ZXJtZWRpYXRlIENBIDExETAPBgNVBAoMCE1TUl9URVNUMQsw\nCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJdWDPPLw/0iunCd\nwKUDA44rg0HRQopEAzsvhAdbTtizLmlTrsbFLwnzLAHSazQ5kYmn3bueBxeu+A9H\ndcW3CaWjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgIEMAoG\nCCqGSM49BAMCA0kAMEYCIQCLq5ePMPEXzs2BIyVd/Bcms/piK5ZEFMvW3bJfINJ1\n1wIhAPAjlUGg9yBVZlRmQHo8bHutfV2kOPFRT5QeCB3sr4G0\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBjTCCATOgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQDDBhWZW5kb3IgSW50ZXJtZWRp\nYXRlIENBIDIxETAPBgNVBAoMCE1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABDvKRc90bFzzMnCrbamewtphHSnPgwIt/cjaHNaH\ndrrKOc61pPiHFZyDZTn3EryaI/QAodkaU4ZuaZBZqAyTb1mjJjAkMBIGA1UdEwEB\n/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgIEMAoGCCqGSM49BAMCA0gAMEUCIQCn\n8y7EACqeq5/vbm/kkHwkQpRbxk1eiBDMrei5zcv4PQIgXHSQNL/vWuxWiV6PCuj1\nvFZRtUAMViK3l1VLh8B4AtI=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBfDCCASGgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjAxMSIwIAYDVQQDDBlWZW5kb3IgUm9vdCBDQSBP\nPU1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBOdPm4HJmdGpKxa5XYODkktSz0uW4ZZI+u1hAQivr4dccHyFpZFQuzOADuiruxFQ\nM1uuTT2tR962nUBBFWyczlOjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQUwDgYDVR0P\nAQH/BAQDAgIEMAoGCCqGSM49BAMCA0kAMEYCIQCVFnoQv1l45SWmveMM1wplOSDc\ngmS816UBx2yimuKuhQIhAPl0UyybFYtNyZwNjHP/oAO2k9we9dqUT1RoJv+X5kwp\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/riot/test/corim/src/comid-riot-ta.json b/scheme/riot/test/corim/src/comid-riot-ta.json new file mode 100644 index 00000000..6c8d3a21 --- /dev/null +++ b/scheme/riot/test/corim/src/comid-riot-ta.json @@ -0,0 +1,23 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000000410701" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "Veraison Project", + "model": "RIOT" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert-path", + "value": "-----BEGIN CERTIFICATE-----\nMIIBoDCCAUWgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwQzEhMB8GA1UEAwwYVmVu\nZG9yIEludGVybWVkaWF0ZSBDQSAyMREwDwYDVQQKDAhNU1JfVEVTVDELMAkGA1UE\nBhMCVVMwHhcNMjAxMDIxMDkwMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQD\nDBhWZW5kb3IgSW50ZXJtZWRpYXRlIENBIDExETAPBgNVBAoMCE1TUl9URVNUMQsw\nCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJdWDPPLw/0iunCd\nwKUDA44rg0HRQopEAzsvhAdbTtizLmlTrsbFLwnzLAHSazQ5kYmn3bueBxeu+A9H\ndcW3CaWjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgIEMAoG\nCCqGSM49BAMCA0kAMEYCIQCLq5ePMPEXzs2BIyVd/Bcms/piK5ZEFMvW3bJfINJ1\n1wIhAPAjlUGg9yBVZlRmQHo8bHutfV2kOPFRT5QeCB3sr4G0\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBjTCCATOgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjBDMSEwHwYDVQQDDBhWZW5kb3IgSW50ZXJtZWRp\nYXRlIENBIDIxETAPBgNVBAoMCE1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABDvKRc90bFzzMnCrbamewtphHSnPgwIt/cjaHNaH\ndrrKOc61pPiHFZyDZTn3EryaI/QAodkaU4ZuaZBZqAyTb1mjJjAkMBIGA1UdEwEB\n/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgIEMAoGCCqGSM49BAMCA0gAMEUCIQCn\n8y7EACqeq5/vbm/kkHwkQpRbxk1eiBDMrei5zcv4PQIgXHSQNL/vWuxWiV6PCuj1\nvFZRtUAMViK3l1VLh8B4AtI=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBfDCCASGgAwIBAgIFAQIDBAUwCgYIKoZIzj0EAwIwMTEiMCAGA1UEAwwZVmVu\nZG9yIFJvb3QgQ0EgTz1NU1JfVEVTVDELMAkGA1UEBhMCVVMwHhcNMjAxMDIxMDkw\nMTA2WhcNMzAxMDE5MDkwMTA2WjAxMSIwIAYDVQQDDBlWZW5kb3IgUm9vdCBDQSBP\nPU1TUl9URVNUMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBOdPm4HJmdGpKxa5XYODkktSz0uW4ZZI+u1hAQivr4dccHyFpZFQuzOADuiruxFQ\nM1uuTT2tR962nUBBFWyczlOjJjAkMBIGA1UdEwEB/wQIMAYBAf8CAQUwDgYDVR0P\nAQH/BAQDAgIEMAoGCCqGSM49BAMCA0kAMEYCIQCVFnoQv1l45SWmveMM1wplOSDc\ngmS816UBx2yimuKuhQIhAPl0UyybFYtNyZwNjHP/oAO2k9we9dqUT1RoJv+X5kwp\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/riot/test/corim/src/corim-riot.json b/scheme/riot/test/corim/src/corim-riot.json new file mode 100644 index 00000000..f0b1eed0 --- /dev/null +++ b/scheme/riot/test/corim/src/corim-riot.json @@ -0,0 +1,4 @@ +{ + "corim-id": "00000000-0000-0000-4107-000000000000", + "profile": "tag:veraison-project.com,2026:riot" +} diff --git a/scheme/riot/test/corim/src/corims.yaml b/scheme/riot/test/corim/src/corims.yaml new file mode 100644 index 00000000..3763d573 --- /dev/null +++ b/scheme/riot/test/corim/src/corims.yaml @@ -0,0 +1,14 @@ +corim: corim-riot +outdir: .. +workdir: ../__build +comids: + riot-valid: + - comid-riot-ta + riot-bad-refvals: + - comid-bad-refvals + riot-bad-no-vendor: + - comid-bad-no-vendor + riot-bad-wrong-vendor: + - comid-bad-wrong-vendor + riot-bad-wrong-key-type: + - comid-bad-wrong-key-type diff --git a/scheme/riot/test/corim/submit-riot-endorsements.sh b/scheme/riot/test/corim/submit-riot-endorsements.sh new file mode 100755 index 00000000..319e8230 --- /dev/null +++ b/scheme/riot/test/corim/submit-riot-endorsements.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +cocli corim submit -i --corim-file corim-riot-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="tag:veraison-project.com,2026:riot"' --auth=none + diff --git a/scheme/riot/test/DeviceCerts.pem b/scheme/riot/test/evidence/evidence.pem similarity index 100% rename from scheme/riot/test/DeviceCerts.pem rename to scheme/riot/test/evidence/evidence.pem diff --git a/scheme/riot/test/evidence/submit-riot-evidence.sh b/scheme/riot/test/evidence/submit-riot-evidence.sh new file mode 100755 index 00000000..2f45c5da --- /dev/null +++ b/scheme/riot/test/evidence/submit-riot-evidence.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +EVIDENCE_FILE="$THIS_DIR/evidence.pem" +EVIDENCE_CONTENT_TYPE='application/pem-certificate-chain' + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession?nonce=byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA== 2>/dev/null | grep "location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H "content-type: $EVIDENCE_CONTENT_TYPE" --data-binary @"$EVIDENCE_FILE" https://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/riot/test_vars.go b/scheme/riot/test_vars.go new file mode 100644 index 00000000..1a601d53 --- /dev/null +++ b/scheme/riot/test_vars.go @@ -0,0 +1,24 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package riot + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-riot-bad-no-vendor.cbor + corimRiotBadNoVendor []byte + + //go:embed test/corim/corim-riot-bad-refvals.cbor + corimRiotBadRefvals []byte + + //go:embed test/corim/corim-riot-bad-wrong-key-type.cbor + corimRiotBadWrongKeyType []byte + + //go:embed test/corim/corim-riot-bad-wrong-vendor.cbor + corimRiotBadWrongVendor []byte + + //go:embed test/corim/corim-riot-valid.cbor + corimRiotValid []byte +) diff --git a/scheme/sevsnp/Makefile b/scheme/sevsnp/Makefile index 68ba5f08..2502cdbc 100644 --- a/scheme/sevsnp/Makefile +++ b/scheme/sevsnp/Makefile @@ -1,4 +1,4 @@ -# Copyright 2025 Contributors to the Veraison project. +# Copyright 2025-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 .DEFAULT_GOAL := test diff --git a/scheme/sevsnp/README.md b/scheme/sevsnp/README.md deleted file mode 100644 index 63d3967e..00000000 --- a/scheme/sevsnp/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# SEV-SNP scheme - -This scheme supports the provisioning of reference values and appraisal of evidence. It is suitable for anyone performing verification of simple SEV-SNP evidence. - -## Installation - -It doesn't need any specific install instructions, it gets deployed along with other schemes. -``` -make really-clean && make native-deploy -``` - -## Usage example - -Following is an example of how to interface with this scheme/plugin. The workflow involves using cocli to submit Reference Values and [ratsd](https://github.com/veraison/ratsd) to submit Evidence. - -Generating Reference Values and Evidence is beyond this project's scope. Please see [go-gen-ref](https://github.com/jraman567/go-gen-ref) for creating Reference Values for SEV-SNP; ratsd generates Evidence. - -### Provisioning Trust Anchor -``` -cocli comid create --template scheme/sevsnp/test/ta-prov.json -cocli corim create -m ta-prov.cbor -t corimMini.json -o ta.cbor -cocli corim submit --corim-file=ta.cbor --api-server="https://localhost:9443/endorsement-provisioning/v1/submit" --media-type="application/corim-unsigned+cbor; profile=\"https://amd.com/ark\"" -``` - -### Provisioning Reference Values -``` -cocli corim submit --corim-file=scheme/sevsnp/test/refval-prov.cbor --api-server="https://localhost:9443/endorsement-provisioning/v1/submit" --media-type="application/corim-unsigned+cbor; profile=\"https://amd.com/ark\"" -``` - -### Submitting Evidence -``` -git clone https://github.com/veraison/ratsd.git -cd ratsd; go build -# From the following command, note down the nonce (in the body) and -# session-id (location in the header), and save them as NONCE and -# SESSION_ID environment variables respectively -curl -sSk -X POST "https://:8443/challenge-response/v1/newSession?nonceSize=64" -H "accept: application/vnd.veraison.challenge-response-session+json" -i -EVIDENCE_TOKEN=$(curl -sS -X POST http://:8895/ratsd/chares -H "Content-Type: application/vnd.veraison.chares+json" -d "{\"nonce\":\"$NONCE\"}") -ATTESTATION_RESULT=$(curl -sSk -X POST -H "https://localhost:8443/$SESSION_ID \ - -H "accept: application/vnd.veraison.challenge-response-session+json" \ - -H 'Content-Type: application/eat+cwt; eat_profile="tag:github.com,2025:veraison/ratsd/cmw"' \ - -H "Host: localhost:8443" \ - --data-raw "$EVIDENCE_TOKEN") -echo $ATTESTATION_RESULT -``` - -## Result -The result is in JWT format. We can print and verify the result using the [ARC tool](https://github.com/veraison/ear/tree/main/arc) as follows. -``` -go install github.com/veraison/ear/arc@latest -arc print result.jwt -``` -The trustworthiness vector, as shown below, summarizes the result of verification. -``` - "SEVSNP": { - "ear.appraisal-policy-id": "policy:SEVSNP", - "ear.status": "affirming", - "ear.trustworthiness-vector": { - "configuration": 0, - "executables": 0, - "file-system": 0, - "hardware": 2, - "instance-identity": 0, - "runtime-opaque": 2, - "sourced-data": 0, - "storage-opaque": 0 - }, -``` \ No newline at end of file diff --git a/scheme/sevsnp/common.go b/scheme/sevsnp/common.go deleted file mode 100644 index 8e196eaf..00000000 --- a/scheme/sevsnp/common.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package sevsnp - -import ( - "encoding/base64" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "reflect" - "strconv" - - "github.com/google/go-sev-guest/abi" - "github.com/google/go-sev-guest/kds" - "github.com/google/go-sev-guest/proto/sevsnp" - "github.com/veraison/cmw" - "github.com/veraison/corim/comid" - "github.com/veraison/corim/corim" - "github.com/veraison/ratsd/tokens" - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -var ( - ErrCertificateReadFailure = errors.New("failed to read certificate") - ErrMissingCertChain = errors.New("evidence missing certificate chain") - ErrMissingCMW = errors.New("CMW not found in evidence token") -) - -// measurementByUintKey looks up comid.Measurement in a CoMID by its MKey. -// -// If no measurements are found, returns nil and no error. Otherwise, -// returns the error encountered. -func measurementByUintKey(refVal comid.ValueTriple, - key uint64) (*comid.Measurement, error) { - for _, m := range refVal.Measurements.Values { - if m.Key == nil || !m.Key.IsSet() || - m.Key.Type() != comid.UintType { - continue - } - - k, err := m.Key.GetKeyUint() - if err != nil { - return nil, err - } - - if k == key { - return &m, nil - } - } - - return nil, nil -} - -// comidFromJson accepts a CoRIM in JSON format and returns its first CoMID -// -// Returns error if there are more than a single CoMID, or passes on -// error from corim routine. -func comidFromJson(buf []byte) (*comid.Comid, error) { - extractedCorim, err := corim.UnmarshalUnsignedCorimFromJSON(buf) - if err != nil { - return nil, err - } - - if len(extractedCorim.Tags) > 1 { - return nil, errors.New("too many tags") - } - - extractedComid, err := corim.UnmarshalComidFromCBOR( - extractedCorim.Tags[0].Content, - extractedCorim.Profile, - ) - - if err != nil { - return nil, err - } - - return extractedComid, nil -} - -func parseCertificateChainFromEvidence(tsm *tokens.TSMReport) (*sevsnp.CertificateChain, error) { - var certTable abi.CertTable - - if len(tsm.AuxBlob) == 0 { - return nil, ErrMissingCertChain - } - - if err := certTable.Unmarshal(tsm.AuxBlob); err != nil { - return nil, err - } - - return certTable.Proto(), nil -} - -func readCert(cert []byte) ([]byte, error) { - if len(cert) == 0 { - return nil, errors.New("empty certificate") - } - - block, _ := pem.Decode(cert) - if block == nil || block.Type != "CERTIFICATE" { - return nil, ErrCertificateReadFailure - } - return block.Bytes, nil -} - -func parseAttestationToken(token *proto.AttestationToken) (*tokens.TSMReport, error) { - var ( - err error - tsm = new(tokens.TSMReport) - cmwCollection cmw.CMW - ) - - switch token.MediaType { - case EvidenceMediaTypeTSMCbor: - err = tsm.FromCBOR(token.Data) - if err != nil { - return nil, err - } - case EvidenceMediaTypeTSMJson: - err = tsm.FromJSON(token.Data) - if err != nil { - return nil, err - } - case EvidenceMediaTypeRATSd: - eat := make(map[string]interface{}) - - err = json.Unmarshal(token.Data, &eat) - if err != nil { - return nil, err - } - - cmwBase64, ok := eat["cmw"].(string) - if !ok { - return nil, handler.BadEvidence(ErrMissingCMW) - } - - cmwJson, err := base64.StdEncoding.DecodeString(cmwBase64) - if err != nil { - return nil, err - } - - err = cmwCollection.UnmarshalJSON(cmwJson) - if err != nil { - return nil, err - } - - cmwMonad, err := cmwCollection.GetCollectionItem("tsm-report") - if err != nil { - return nil, err - } - - cmwType, err := cmwMonad.GetMonadType() - if err != nil { - return nil, err - } - if cmwType != "application/vnd.veraison.configfs-tsm+json" { - return nil, fmt.Errorf("unexpected CMW type: %s", cmwType) - } - cmwValue, err := cmwMonad.GetMonadValue() - if err != nil { - return nil, err - } - - err = tsm.FromJSON(cmwValue) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("unexpected media type: %s", token.MediaType) - } - - return tsm, nil -} - -// transformSVNtoTCB extracts TCB from the supplied SVN. SEV-SNP's TCB_VERSION -// is a composite version; it's bitfield consisting of SVNs from various firmware components -func transformSVNtoTCB(svn comid.SVN) (*kds.TCBParts, error) { - var ( - tcbVersion uint64 - err error - tcbParts kds.TCBParts - ) - - // ToDo: following is a circuitous way to obtain the 64-bit TCB integer value - // from SVN. Consider updating the SVN type to return a 64-bit value - switch v := svn.Value.(type) { - case *comid.TaggedSVN: - tcbString := v.String() - tcbVersion, err = strconv.ParseUint(tcbString, 10, 64) - case *comid.TaggedMinSVN: - tcbString := v.String() - tcbVersion, err = strconv.ParseUint(tcbString, 10, 64) - default: - err = fmt.Errorf("unsupported SVN type: %v", reflect.TypeOf(svn.Value)) - } - - if err != nil { - return nil, err - } - - tcbParts = kds.DecomposeTCBVersion(kds.TCBVersion(tcbVersion)) - - return &tcbParts, nil -} diff --git a/scheme/sevsnp/corim.go b/scheme/sevsnp/corim.go new file mode 100644 index 00000000..dd6edf82 --- /dev/null +++ b/scheme/sevsnp/corim.go @@ -0,0 +1,111 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package sevsnp + +import ( + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/services/scheme/common" +) + +const ( + ProfileString = "tag:amd.com,2024:snp-corim-profile" + ArkProfileString = "https://amd.com/ark" +) + +func validateTrustAnchorEnvironment(env *comid.Environment) error { + if env.Class == nil { + return errors.New("missing class") + } + + if env.Class.Vendor == nil { + return errors.New("missing vendor") + } + + if env.Class.Model == nil { + return errors.New("missing model") + } + + return nil +} + +func validateReferenceValueEnvironment(env *comid.Environment) error { + if env.Class == nil { + return errors.New("missing class") + } + + if env.Class.ClassID == nil { + return errors.New("missing class ID") + } + + if env.Class.ClassID.Type() != comid.OIDType { + return fmt.Errorf("class ID: expected OID, got %s", env.Class.ClassID.Type()) + } + + if env.Instance == nil { + return errors.New("missing instance") + } + + if env.Instance.Type() != comid.BytesType { + return fmt.Errorf("instance: expected bytes, got %s", env.Instance.Type()) + } + + return nil +} + +func validateCryptoKeys(keys []*comid.CryptoKey) error { + for _, key := range keys { + if key.Type() != comid.PKIXBase64CertPathType && key.Type() != comid.PKIXBase64CertType { + return fmt.Errorf("key must be a cert or a cert path, found: %s", key.Type()) + } + } + + return nil +} + +func validateMeasurements(measurements []comid.Measurement) error { + for i, mea := range measurements { + if mea.Key == nil { + return fmt.Errorf("measurement %d: mkey not set", i) + } + + if mea.Key.Type() != comid.UintType { + return fmt.Errorf("measurement %d: mkey type: expected uint, got %s", i, mea.Key.Type()) + } + } + + return nil +} + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + arkProfileID, err := eat.NewProfile(ArkProfileString) + if err != nil { + panic(err) + } + + validator := &common.TriplesValidator{ + TAEnviromentValidator: validateTrustAnchorEnvironment, + RefValEnviromentValidator: validateReferenceValueEnvironment, + CryptoKeysValidator: validateCryptoKeys, + MeasurementsValidator: validateMeasurements, + } + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } + + if err := corim.RegisterProfile(arkProfileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/sevsnp/corim_test.go b/scheme/sevsnp/corim_test.go new file mode 100644 index 00000000..90b70ee9 --- /dev/null +++ b/scheme/sevsnp/corim_test.go @@ -0,0 +1,41 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package sevsnp + +import ( + _ "embed" + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "ok", + Input: corimSevsnpValid, + }, + { + Title: "bad TA env no model", + Input: corimSevsnpBadTaNoModel, + Err: "missing model", + }, + { + Title: "bad TA env no vendor", + Input: corimSevsnpBadTaNoVendor, + Err: "missing vendor", + }, + { + Title: "bad RefVal no mkey", + Input: corimSevsnpBadRefvalNoKey, + Err: "mkey not set", + }, + { + Title: "bad RefVal mkey type", + Input: corimSevsnpBadRefvalKey, + Err: "mkey type: expected uint, got oid", + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/sevsnp/endorsement_handler.go b/scheme/sevsnp/endorsement_handler.go deleted file mode 100644 index 0053d9d4..00000000 --- a/scheme/sevsnp/endorsement_handler.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package sevsnp - -import ( - "errors" - "mime" - - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common" -) - -// EndorsementHandler implements the IEndorsementHandler interface for SEVSNP scheme -type EndorsementHandler struct{} - -// Init initializes the endorsement handler instance. no-op for SEVSNP -func (o EndorsementHandler) Init(params handler.EndorsementHandlerParams) error { - return nil // no-op -} - -// Close closes the endorsement handler instance. no-op for SEVSNP -func (o EndorsementHandler) Close() error { - return nil // no-op -} - -// GetName returns the name of the endorsement handler -func (o EndorsementHandler) GetName() string { - return SchemeName -} - -// GetAttestationScheme returns the scheme name -func (o EndorsementHandler) GetAttestationScheme() string { - return SchemeName -} - -// GetSupportedMediaTypes returns the media types supported for SEVSNP endorsements -func (o EndorsementHandler) GetSupportedMediaTypes() []string { - return EndorsementMediaTypes -} - -// Decode decodes the supplied endorsement as an unsigned CoRIM -func (o EndorsementHandler) Decode(data []byte, mediaType string, caCertPool []byte) (*handler.EndorsementHandlerResponse, error) { - extractor := &Extractor{} - - if mediaType != "" { - mt, _, err := mime.ParseMediaType(mediaType) - if err != nil { - return nil, err - } - - // Use signed decoder for signed CoRIM - if mt == "application/rim+cose" { - return common.SignedCorimDecoder(data, extractor, caCertPool) - } - } - - // Default to unsigned CoRIM decoder - return common.UnsignedCorimDecoder(data, extractor) -} - -func (o EndorsementHandler) CoservRepackage(coservQuery string, resultSet []string) ([]byte, error) { - return nil, errors.New("SEV-SNP CoservRepackage not implemented") -} diff --git a/scheme/sevsnp/endorsement_handler_test.go b/scheme/sevsnp/endorsement_handler_test.go deleted file mode 100644 index fa1ce7c3..00000000 --- a/scheme/sevsnp/endorsement_handler_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package sevsnp - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDecoder_GetName(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetName() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetAttestationScheme(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetAttestationScheme() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetSupportedMediaTypes(t *testing.T) { - d := &EndorsementHandler{} - - expected := EndorsementMediaTypes - - actual := d.GetSupportedMediaTypes() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_Decode_OK(t *testing.T) { - d := &EndorsementHandler{} - - _, err := d.Decode(unsignedCorimSevSnp, "", nil) - assert.NoError(t, err) -} diff --git a/scheme/sevsnp/evidence_handler.go b/scheme/sevsnp/evidence_handler.go deleted file mode 100644 index 9b37a71e..00000000 --- a/scheme/sevsnp/evidence_handler.go +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package sevsnp - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/google/go-sev-guest/abi" - "github.com/google/go-sev-guest/proto/sevsnp" - "github.com/google/go-sev-guest/verify" - "github.com/google/go-sev-guest/verify/trust" - sevsnpParser "github.com/jraman567/go-gen-ref/cmd/sevsnp" - "github.com/veraison/corim/comid" - "github.com/veraison/corim/corim" - "github.com/veraison/ear" - "github.com/veraison/ratsd/tokens" - "github.com/veraison/services/handler" - "github.com/veraison/services/log" - "github.com/veraison/services/proto" -) - -var ( - ErrNoARK = errors.New("missing ARK certificate in evidence") - ErrNoASK = errors.New("missing ASK certificate in evidence") - ErrNoVEK = errors.New("evidence must supply VLEK or VCEK") - ErrNoVCEK = errors.New("VCEK is missing") - ErrNoVLEK = errors.New("VLEK is missing") - ErrTAMismatch = errors.New("evidence Trust Anchor (ARK) doesn't match the provisioned one") - ErrNoProvisionedTA = errors.New("missing provisioned Trust Anchor") - ErrNoProvisionedRV = errors.New("reference value unavailable for attester") - ErrBadSigningKey = errors.New("bad signing key in attestation report") - ErrMismatchedReportedTCB = errors.New("reported TCB in evidence doesn't match reference") - ErrReferenceMissingSVN = errors.New("reference doesn't have SVN") - ErrEvidenceMissingSVN = errors.New("evidence doesn't have SVN") -) - -const ( - ReportSigningKeyVcek = 0 - ReportSigningKeyVlek = 1 -) - -// EvidenceHandler implements the IEvidenceHandler interface for SEVSNP -type EvidenceHandler struct { -} - -// GetName returns the name of this evidence handler instance -func (o EvidenceHandler) GetName() string { - return "sevsnp-evidence-handler" -} - -// GetAttestationScheme returns the attestation scheme -func (o EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -// GetSupportedMediaTypes returns the supported media types for the SEVSNP scheme -func (o EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func transformEvidenceToCorim(token *proto.AttestationToken) (*corim.UnsignedCorim, error) { - tsm, err := parseAttestationToken(token) - if err != nil { - return nil, err - } - - reportProto, err := abi.ReportToProto(tsm.OutBlob) - if err != nil { - return nil, err - } - - evComid, err := sevsnpParser.ReportToComid(reportProto, 0) - if err != nil { - return nil, err - } - - err = evComid.Valid() - if err != nil { - return nil, err - } - - evCorim := corim.UnsignedCorim{} - evCorim.SetProfile(EndorsementMediaTypeRV) - evCorim.AddComid(evComid) - - return &evCorim, nil -} - -// ExtractClaims converts evidence in tsm-report format to our -// "internal representation", which is in CoRIM format. -func (o EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - _ []string, -) (map[string]interface{}, error) { - var claimsSet map[string]interface{} - - evCorim, err := transformEvidenceToCorim(token) - if err != nil { - return nil, err - } - - evJson, err := evCorim.ToJSON() - if err != nil { - return nil, err - } - - err = json.Unmarshal(evJson, &claimsSet) - if err != nil { - return nil, err - } - - return claimsSet, nil -} - -func extractProvisionedTA(trustAnchors []string) (*comid.CryptoKey, error) { - var ( - taEndorsement *handler.Endorsement - avk comid.KeyTriple - ) - - for i, t := range trustAnchors { - var endorsement handler.Endorsement - - if err := json.Unmarshal([]byte(t), &endorsement); err != nil { - return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err) - } - - if endorsement.Type == handler.EndorsementType_VERIFICATION_KEY { - taEndorsement = &endorsement - break - } - } - - if taEndorsement == nil { - return nil, handler.BadEvidence(ErrNoProvisionedTA) - } - - err := json.Unmarshal(taEndorsement.Attributes, &avk) - if err != nil { - return nil, err - } - - // The StoreHandler takes care of ensuring that only one TA is - // supplied, we don't have to re-check it here. - provisionedArk := avk.VerifKeys[0] - - return provisionedArk, nil -} - -func validateCertificateChain(certChain *sevsnp.CertificateChain) error { - if len(certChain.GetArkCert()) == 0 { - return handler.BadEvidence(ErrNoARK) - } - - if len(certChain.GetAskCert()) == 0 { - return handler.BadEvidence(ErrNoASK) - } - - if len(certChain.GetVcekCert()) == 0 && len(certChain.GetVlekCert()) == 0 { - return handler.BadEvidence(ErrNoVEK) - } - - return nil -} - -func validateTA(certChain *sevsnp.CertificateChain, provisionedArk *comid.CryptoKey) error { - if !bytes.Equal(certChain.GetArkCert(), []byte(provisionedArk.String())) { - return handler.BadEvidence(ErrTAMismatch) - } - - return nil -} - -func validateReportIntegrity(tsm *tokens.TSMReport, certChain *sevsnp.CertificateChain) error { - var ( - ark, ask, vcek, vlek []byte - attestation sevsnp.Attestation - ) - - // options: options to use when verifying SEV-SNP evidence - // not feasible to enable certificate fetching and - // checking revocations as AMD KDS rate-limits requests - options := verify.Options{ - Getter: trust.DefaultHTTPSGetter(), - Now: time.Now(), - DisableCertFetching: true, - CheckRevocations: false, - } - - protoReport, err := abi.ReportToProto(tsm.OutBlob) - if err != nil { - return err - } - attestation.Report = protoReport - - if ark, err = readCert(certChain.GetArkCert()); err != nil { - return fmt.Errorf("can't read ARK to validate cert chain: %w", err) - } - - if ask, err = readCert(certChain.GetAskCert()); err != nil { - return fmt.Errorf("can't read ASK to validate cert chain: %w", err) - } - - signerInfo, err := abi.ParseSignerInfo(protoReport.GetSignerInfo()) - if err != nil { - return err - } - - switch signerInfo.SigningKey { - case ReportSigningKeyVlek: - if len(certChain.GetVlekCert()) == 0 { - return ErrNoVLEK - } - if vlek, err = readCert(certChain.GetVlekCert()); err != nil { - return fmt.Errorf("can't read VLEK to validate cert chain: %w", err) - } - attestation.CertificateChain = &sevsnp.CertificateChain{VlekCert: vlek, AskCert: ask, ArkCert: ark} - case ReportSigningKeyVcek: - if len(certChain.GetVcekCert()) == 0 { - return ErrNoVCEK - } - if vcek, err = readCert(certChain.GetVcekCert()); err != nil { - return fmt.Errorf("can't read VCEK to validate cert chain: %w", err) - } - attestation.CertificateChain = &sevsnp.CertificateChain{VcekCert: vcek, AskCert: ask, ArkCert: ark} - default: - return ErrBadSigningKey - } - - err = verify.SnpAttestation(&attestation, &options) - if err != nil { - return handler.BadEvidence(err) - } - - return nil -} - -func validateSessionNonce(tsm *tokens.TSMReport, sessionNonce []byte) error { - reportProto, err := abi.ReportToProto(tsm.OutBlob) - if err != nil { - return err - } - - evNonce := reportProto.GetReportData() - - if !bytes.Equal(evNonce, sessionNonce) { - return handler.BadEvidence(fmt.Errorf("nonce in the evidence doesn't match the session nonce. evidence: 0x%x vs session: 0x%x", evNonce, sessionNonce)) - } - - return nil -} - -// ValidateEvidenceIntegrity confirms the integrity of evidence by doing the following: -// - verifies that the TA in the evidence matches the provisioned TA -// - confirms the integrity of the certificate chain -// - validates the integrity of evidence by checking its signature -func (o EvidenceHandler) ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - _ []string, -) error { - var ( - tsm *tokens.TSMReport - provisionedArk *comid.CryptoKey - certChain *sevsnp.CertificateChain - err error - ) - - if tsm, err = parseAttestationToken(token); err != nil { - return err - } - - if provisionedArk, err = extractProvisionedTA(trustAnchors); err != nil { - return err - } - - if certChain, err = parseCertificateChainFromEvidence(tsm); err != nil { - return err - } - - if err := validateCertificateChain(certChain); err != nil { - return err - } - - if err := validateTA(certChain, provisionedArk); err != nil { - return err - } - - if err := validateSessionNonce(tsm, token.Nonce); err != nil { - return err - } - - return validateReportIntegrity(tsm, certChain) -} - -// refvalToComidTriple converts extracted reference values to CoMID value triple -func refvalToComidTriple(endorsementsStrings []string) (*comid.ValueTriple, error) { - var ( - refValEndorsement *handler.Endorsement - rv comid.ValueTriple - ) - - for i, e := range endorsementsStrings { - var endorsement handler.Endorsement - - if err := json.Unmarshal([]byte(e), &endorsement); err != nil { - return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err) - } - - if endorsement.Type == handler.EndorsementType_REFERENCE_VALUE { - refValEndorsement = &endorsement - break - } - } - - if refValEndorsement == nil { - return nil, handler.BadEvidence(ErrNoProvisionedRV) - } - - err := json.Unmarshal(refValEndorsement.Attributes, &rv) - if err != nil { - return nil, err - } - - return &rv, nil -} - -// evidenceToComidTriple converts claim set to CoMID value triple -func evidenceToComidTriple(ec *proto.EvidenceContext) (*comid.ValueTriple, error) { - evCorimJson, err := json.Marshal(ec.Evidence.AsMap()) - if err != nil { - return nil, err - } - - evComid, err := comidFromJson(evCorimJson) - if err != nil { - return nil, err - } - - return &evComid.Triples.ReferenceValues.Values[0], nil -} - -// compareMeasurements checks if two given comid.Measurement variables are equal. -func compareMeasurements(refM comid.Measurement, evM comid.Measurement) bool { - // RawValue comparison - if refM.Val.RawValue != nil { - if evM.Val.RawValue == nil { - return false - } - - refDigest, _ := refM.Val.RawValue.GetBytes() - return evM.Val.RawValue.CompareAgainstReference(refDigest, nil) - } - - // Digests comparison - if refM.Val.Digests != nil { - if evM.Val.Digests == nil { - return false - } - - return evM.Val.Digests.CompareAgainstReference(*refM.Val.Digests) - } - - // SVN comparison - if refM.Val.SVN != nil { - if evM.Val.SVN == nil { - log.Debugf("evidence doesn't have SVN") - return false - } - - if c, ok := evM.Val.SVN.Value.(*comid.TaggedSVN); ok { - if r, ok := refM.Val.SVN.Value.(*comid.TaggedSVN); ok { - return c.CompareAgainstRefSVN(*r) - } else if r, ok := refM.Val.SVN.Value.(*comid.TaggedMinSVN); ok { - return c.CompareAgainstRefMinSVN(*r) - } else { - log.Debugf("unknown refVal SVN type") - return false - } - } else if c, ok := evM.Val.SVN.Value.(*comid.TaggedMinSVN); ok { - if r, ok := refM.Val.SVN.Value.(*comid.TaggedMinSVN); ok { - return c.Equal(*r) - } - log.Debugf("can't compare TaggedMinSVN against TaggedSVN") - return false - } else { - log.Debugf("unknown evidence SVN type") - return false - } - } - - return true -} - -func compareTcb(refM comid.Measurement, evM comid.Measurement) bool { - if refM.Val.SVN == nil { - log.Errorf("%w", ErrReferenceMissingSVN) - return false - } - - if evM.Val.SVN == nil { - log.Errorf("%w", ErrEvidenceMissingSVN) - return false - } - - refTcbParts, err := transformSVNtoTCB(*refM.Val.SVN) - if err != nil { - log.Errorf("could not transform reference SVN to TCB parts: %v", err) - return false - } - - evTcbParts, err := transformSVNtoTCB(*evM.Val.SVN) - if err != nil { - log.Errorf("could not transform evidence SVN to TCB parts: %v", err) - } - - if evTcbParts.BlSpl < refTcbParts.BlSpl || - evTcbParts.SnpSpl < refTcbParts.SnpSpl || - evTcbParts.TeeSpl < refTcbParts.TeeSpl || - evTcbParts.UcodeSpl < refTcbParts.UcodeSpl { - return false - } - - return true -} - -// AppraiseEvidence confirms if the claims in the evidence match with the provisioned -// reference values. -// -// Appraisal can confirm if the evidence is genuinely generated by AMD -// hardware and if SEV-SNP enables memory encryption. As such, set the -// "Hardware" and "RuntimeOpaque" values in the trustworthiness vector; -// we can't infer other aspects of the vector from SEV-SNP evidence alone. -func (o EvidenceHandler) AppraiseEvidence( - ec *proto.EvidenceContext, - endorsementsStrings []string, -) (*ear.AttestationResult, error) { - var ( - err error - evidenceMap map[string]interface{} - ) - - refVal, err := refvalToComidTriple(endorsementsStrings) - if err != nil { - return nil, err - } - - evidence, err := evidenceToComidTriple(ec) - if err != nil { - return nil, err - } - - result := handler.CreateAttestationResult(SchemeName) - - appraisal := result.Submods[SchemeName] - - // Init TrustVector to default values - appraisal.TrustVector.InstanceIdentity = ear.NoClaim - appraisal.TrustVector.Executables = ear.NoClaim - appraisal.TrustVector.Configuration = ear.NoClaim - appraisal.TrustVector.FileSystem = ear.NoClaim - appraisal.TrustVector.StorageOpaque = ear.NoClaim - appraisal.TrustVector.SourcedData = ear.NoClaim - appraisal.TrustVector.Hardware = ear.UnsafeHardwareClaim - appraisal.TrustVector.RuntimeOpaque = ear.VisibleMemoryRuntimeClaim - -claimsLoop: - for _, m := range refVal.Measurements.Values { - var ( - k uint64 - em *comid.Measurement - ) - - k, err = m.Key.GetKeyUint() - if err != nil { - break - } - - // We can skip validating certain claims for the following reasons: - // - POLICY ToDo: Do we need to test individual policy features? - // - CURRENT_TCB is informational only. It's best handled by policy - // - PLATFORM_INFO ToDO: Do we need to test individual platform features? - // - REPORT_DATA is a nonce supplied by user for freshness. It's used - // for freshness verification, and verified as part of - // evidence integrity check (session nonce check). - // - REPORT_ID is ephemeral, so we can't use it for verification. - // - REPORT_ID_MA is also ephemeral, used for migration - // - CHIP_ID is unique to an specific attester, but reference values could be used more generally - // - Current Version (CURRENT_MAJOR/MINOR/BUILD) should already be part of REPORTED_TCB. - // ToDo: It is a good idea to test it anyway, but the Version type only tests for - // equality, and this would trigger spurious failures - // - COMMITTED_TCB is informational, used by the host to advance REPORTED_TCB - if k == mKeyPolicy || - k == mKeyCurrentTcb || - k == mKeyPlatformInfo || - k == mKeyReportData || - k == mKeyReportID || - k == mKeyReportIDMA || - k == mKeyChipID || - k == mKeyCommittedTcb || - k == mKeyCurrentVersion || - k == mKeyCommittedVersion { - continue - } - - em, err = measurementByUintKey(*evidence, k) - if err != nil { - break - } - - if em == nil { - err = fmt.Errorf("MKey %d not found in Evidence", k) - break - } - - switch k { - case mKeyReportedTcb: - if !compareTcb(m, *em) { - err = ErrMismatchedReportedTCB - break claimsLoop - } - case mKeyLaunchTcb: - reportedTcb, err := measurementByUintKey(*evidence, mKeyReportedTcb) - if err != nil { - break claimsLoop - } - if !compareTcb(*reportedTcb, *em) { - // ToDo: Is this a failure condition? - log.Errorf("TEE launched with older TCB version") - } - default: - if !compareMeasurements(m, *em) { - err = fmt.Errorf("MKey %d in reference value doesn't match with evidence", k) - break claimsLoop - } - } - } - - if err == nil { - appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim - appraisal.TrustVector.RuntimeOpaque = ear.EncryptedMemoryRuntimeClaim - } - - appraisal.UpdateStatusFromTrustVector() - - evidenceJson, err := json.Marshal(evidence) - if err != nil { - return nil, err - } - - err = json.Unmarshal(evidenceJson, &evidenceMap) - if err != nil { - return nil, err - } - - appraisal.VeraisonAnnotatedEvidence = &evidenceMap - - return result, err -} diff --git a/scheme/sevsnp/evidence_handler_test.go b/scheme/sevsnp/evidence_handler_test.go deleted file mode 100644 index 5597c286..00000000 --- a/scheme/sevsnp/evidence_handler_test.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package sevsnp - -import ( - "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/veraison/ear" - "os" - "testing" - - "github.com/stretchr/testify/require" - "github.com/veraison/services/proto" -) - -var testNonce = []byte{ - 77, 73, 68, 66, 78, 72, 50, 56, - 105, 105, 111, 105, 115, 106, 80, 121, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 77, 73, 68, 66, 78, 72, 50, 56, - 105, 105, 111, 105, 115, 106, 80, 121, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, -} - -var testBadNonce = []byte{ - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, - 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, -} - -type sevSnpEvidence struct { - FileName string - MediaType string -} - -var testEvidenceList = []sevSnpEvidence{ - {"test/sevsnp-ratsd-token", EvidenceMediaTypeRATSd}, - {"test/sevsnp-tsm-report.json", EvidenceMediaTypeTSMJson}, - {"test/sevsnp-tsm-report.cbor", EvidenceMediaTypeTSMCbor}, -} - -func Test_ExtractClaims_ok(t *testing.T) { - for _, evidence := range testEvidenceList { - tokenBytes, err := os.ReadFile(evidence.FileName) - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsement.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: evidence.MediaType, - Nonce: testNonce, - } - ta := string(taEndValBytes) - _, err = handler.ExtractClaims(&token, []string{ta}) - - require.NoError(t, err) - } -} - -func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { - for _, evidence := range testEvidenceList { - tokenBytes, err := os.ReadFile(evidence.FileName) - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsement.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: evidence.MediaType, - Nonce: testNonce, - } - - ta := string(taEndValBytes) - err = handler.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - - assert.NoError(t, err) - } -} - -func Test_ValidateEvidenceIntegrity_BadTA(t *testing.T) { - tokenBytes, err := os.ReadFile("test/sevsnp-ratsd-token") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsement-bad.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: EvidenceMediaTypeRATSd, - Nonce: testNonce, - } - - ta := string(taEndValBytes) - err = handler.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - - assert.EqualError(t, err, "{\"detail\":[\"evidence Trust Anchor (ARK) doesn't match the provisioned one\"],\"detail-type\":\"error\",\"error\":\"bad evidence\"}") -} - -func Test_ValidateEvidenceIntegrity_BadNonce(t *testing.T) { - tokenBytes, err := os.ReadFile("test/sevsnp-ratsd-token") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsement.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: EvidenceMediaTypeRATSd, - Nonce: testBadNonce, - } - - ta := string(taEndValBytes) - err = handler.ValidateEvidenceIntegrity(&token, []string{ta}, nil) - - assert.EqualError(t, err, "{\"detail\":[\"nonce in the evidence doesn't match the session nonce. evidence: 0x4d4944424e48323869696f69736a5079787878787878787878787878787878784d4944424e48323869696f69736a507978787878787878787878787878787878 vs session: 0x07060504030201000f0e0d0c0b0a090817161514131211101f1e1d1c1b1a1918\"],\"detail-type\":\"error\",\"error\":\"bad evidence\"}") -} - -func Test_AppraiseEvidence_ok(t *testing.T) { - for _, evidence := range testEvidenceList { - tokenBytes, err := os.ReadFile(evidence.FileName) - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsement.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: evidence.MediaType, - Nonce: testNonce, - } - ta := string(taEndValBytes) - claims, err := handler.ExtractClaims(&token, []string{ta}) - require.NoError(t, err) - - claimsJson, err := json.Marshal(claims) - require.NoError(t, err) - - var ec proto.EvidenceContext - ec.TenantId = "0" - ec.TrustAnchorIds = []string{"SEVSNP://ARK-Genoa"} - ec.ReferenceIds = []string{"SEVSNP://0/7699e6ac12ccdfd1dfac70e649ce1f046cb2afbb003438f4cdddfe2ccbe182fa5ffbe8dcdb930454324e10c52c788980"} - err = json.Unmarshal(claimsJson, &ec.Evidence) - require.NoError(t, err) - - endorsementsBytes, err := os.ReadFile("test/refval-endorsement.json") - require.NoError(t, err) - - result, err := handler.AppraiseEvidence(&ec, []string{string(endorsementsBytes)}) - require.NoError(t, err) - - attestation := result.Submods["SEVSNP"] - - assert.Equal(t, ear.TrustTierAffirming, *attestation.Status) - } -} diff --git a/scheme/sevsnp/extractor.go b/scheme/sevsnp/extractor.go deleted file mode 100644 index 240dfb72..00000000 --- a/scheme/sevsnp/extractor.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package sevsnp - -import ( - "encoding/json" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" -) - -type Extractor struct { - Profile string -} - -// RefValExtractor stores the CoMID values triples in the database as-is. -func (o Extractor) RefValExtractor(rvs comid.ValueTriples) ([]*handler.Endorsement, error) { - refVals := make([]*handler.Endorsement, 0, len(rvs.Values)) - - for _, rv := range rvs.Values { - rvAttrs, err := json.Marshal(&rv) - if err != nil { - return nil, err - } - - refVal := &handler.Endorsement{ - Scheme: SchemeName, - Type: handler.EndorsementType_REFERENCE_VALUE, - SubType: "measurements", - Attributes: rvAttrs, - } - - refVals = append(refVals, refVal) - } - - return refVals, nil -} - -// TaExtractor Processes the verification keys supplied in the Endorsement -// -// The trust anchor for SEV-SNP is AMD Root Key (ARK). Stores the key triple in the database as-is. -func (o Extractor) TaExtractor(avk comid.KeyTriple) (*handler.Endorsement, error) { - if len(avk.VerifKeys) > 1 { - return nil, fmt.Errorf("expecting at most one key, got %d keys", len(avk.VerifKeys)) - } - - taAttrs, err := json.Marshal(&avk) - if err != nil { - return nil, err - } - - ta := &handler.Endorsement{ - Scheme: SchemeName, - Type: handler.EndorsementType_VERIFICATION_KEY, - Attributes: taAttrs, - } - - return ta, nil -} - -// SetProfile sets the extractor profile -func (o *Extractor) SetProfile(profile string) { - o.Profile = profile -} diff --git a/scheme/sevsnp/plugin/Makefile b/scheme/sevsnp/plugin/Makefile index c4428d4f..80560fba 100644 --- a/scheme/sevsnp/plugin/Makefile +++ b/scheme/sevsnp/plugin/Makefile @@ -1,13 +1,11 @@ -# Copyright 2025 Contributors to the Veraison project. +# Copyright 2025-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += endorsement-handler - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-sevsnp.plugin +GOPKG := github.com/veraison/services/scheme/sevsnp +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/sevsnp/plugin/combined/Makefile b/scheme/sevsnp/plugin/combined/Makefile deleted file mode 100644 index eb99b10a..00000000 --- a/scheme/sevsnp/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/sevsnp.plugin -GOPKG := github.com/veraison/services/scheme/sevsnp -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/sevsnp/plugin/combined/main.go b/scheme/sevsnp/plugin/combined/main.go deleted file mode 100644 index 17329190..00000000 --- a/scheme/sevsnp/plugin/combined/main.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/sevsnp" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/sevsnp/plugin/endorsement-handler/Makefile b/scheme/sevsnp/plugin/endorsement-handler/Makefile deleted file mode 100644 index fc2cf8da..00000000 --- a/scheme/sevsnp/plugin/endorsement-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/sevsnp-endorsement-handler.plugin -GOPKG := github.com/veraison/services/scheme/sevsnp -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/sevsnp/plugin/evidence-handler/Makefile b/scheme/sevsnp/plugin/evidence-handler/Makefile deleted file mode 100644 index 67e4a5ff..00000000 --- a/scheme/sevsnp/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/sevsnp-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/sevsnp -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/sevsnp/plugin/evidence-handler/main.go b/scheme/sevsnp/plugin/evidence-handler/main.go deleted file mode 100644 index 9ed8f5c4..00000000 --- a/scheme/sevsnp/plugin/evidence-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/sevsnp" -) - -func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - plugin.Serve() -} diff --git a/scheme/sevsnp/plugin/endorsement-handler/main.go b/scheme/sevsnp/plugin/main.go similarity index 61% rename from scheme/sevsnp/plugin/endorsement-handler/main.go rename to scheme/sevsnp/plugin/main.go index d8349094..46141930 100644 --- a/scheme/sevsnp/plugin/endorsement-handler/main.go +++ b/scheme/sevsnp/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, scheme.NewImplementation()) plugin.Serve() } diff --git a/scheme/sevsnp/plugin/store-handler/Makefile b/scheme/sevsnp/plugin/store-handler/Makefile deleted file mode 100644 index c309f787..00000000 --- a/scheme/sevsnp/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2025 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/sevsnp-store-handler.plugin -GOPKG := github.com/veraison/services/scheme/sevsnp -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/sevsnp/plugin/store-handler/main.go b/scheme/sevsnp/plugin/store-handler/main.go deleted file mode 100644 index 63d58c94..00000000 --- a/scheme/sevsnp/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/sevsnp" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/sevsnp/scheme.go b/scheme/sevsnp/scheme.go index 6f2823de..eb8a6617 100644 --- a/scheme/sevsnp/scheme.go +++ b/scheme/sevsnp/scheme.go @@ -1,28 +1,48 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package sevsnp -const ( - SchemeName = "SEVSNP" - EndorsementMediaTypeRV = `application/corim-unsigned+cbor; profile="tag:amd.com,2024:snp-corim-profile"` - // ToDo: check media type for AMD ARK - EndorsementMediaTypeTA = `application/corim-unsigned+cbor; profile="https://amd.com/ark"` - EvidenceMediaTypeTSMCbor = "application/vnd.veraison.tsm-report+cbor" - EvidenceMediaTypeTSMJson = "application/vnd.veraison.configfs-tsm+json" - EvidenceMediaTypeRATSd = `application/eat+cwt; eat_profile="tag:github.com,2025:veraison/ratsd/cmw"` +import ( + "bytes" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "reflect" + "slices" + "strconv" + + "github.com/google/go-sev-guest/abi" + "github.com/google/go-sev-guest/kds" + "github.com/google/go-sev-guest/proto/sevsnp" + sevsnpParser "github.com/jraman567/go-gen-ref/cmd/sevsnp" + "github.com/veraison/cmw" + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/ear" + "github.com/veraison/ratsd/tokens" + "github.com/veraison/services/handler" + "github.com/veraison/services/log" + "github.com/veraison/services/scheme/common" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" ) var ( - EndorsementMediaTypes = []string{ - EndorsementMediaTypeRV, - EndorsementMediaTypeTA, - } + ErrCertificateReadFailure = errors.New("failed to read certificate") + ErrMissingCMW = errors.New("CMW not found in evidence token") + ErrMissingCertChain = errors.New("evidence missing certificate chain") + ErrNoARK = errors.New("missing ARK certificate in evidence") + ErrNoASK = errors.New("missing ASK certificate in evidence") + ErrNoVEK = errors.New("evidence must supply VLEK or VCEK") + ErrTAMismatch = errors.New("evidence Trust Anchor (ARK) doesn't match the provisioned one") - EvidenceMediaTypes = []string{ - EvidenceMediaTypeTSMCbor, - EvidenceMediaTypeTSMJson, - EvidenceMediaTypeRATSd, - } + EndorsementMediaTypeRV = `application/corim-unsigned+cbor; profile="tag:amd.com,2024:snp-corim-profile"` + EvidenceMediaTypeRATSd = `application/eat+cwt; eat_profile="tag:github.com,2025:veraison/ratsd/cmw"` + EvidenceMediaTypeTSMCbor = "application/vnd.veraison.tsm-report+cbor" + EvidenceMediaTypeTSMJson = "application/vnd.veraison.configfs-tsm+json" ) const ( @@ -40,3 +60,561 @@ const ( mKeyCommittedVersion = 3936 mKeyLaunchTcb = 3968 ) + +var Descriptor = handler.SchemeDescriptor{ + Name: "SEVSNP", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + ArkProfileString, + }, + EvidenceMediaTypes: []string{ + EvidenceMediaTypeTSMCbor, + EvidenceMediaTypeTSMJson, + EvidenceMediaTypeRATSd, + }, +} + +type Implementation struct { + logger *zap.SugaredLogger +} + +func NewImplementation() *Implementation { + return &Implementation{ + logger: log.Named(Descriptor.Name), + } +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + tsm, err := parseEvidence(evidence) + if err != nil { + return nil, handler.BadEvidence(err) + } + + certChain, err := parseCertChainFromTSMReport(tsm) + if err != nil { + return nil, handler.BadEvidence(err) + } + + ark, err := readCert(certChain.GetArkCert()) + if err != nil { + return nil, handler.BadEvidence("can't read ARK to compose TA ID: %w", err) + } + + cert, err := x509.ParseCertificate(ark) + if err != nil { + return nil, handler.BadEvidence(err) + } + + return []*comid.Environment{ + { + Class: &comid.Class{ + Vendor: &cert.Subject.Organization[0], + Model: &cert.Subject.CommonName, + }, + }, + }, nil +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + evCorim, err := transformClaimsToCorim(claims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + var ret []*comid.Environment // nolint:prealloc + rvIter, iterErr := evCorim.IterRefVals() + for refVal := range rvIter { + ret = append(ret, &refVal.Environment) + } + if err := iterErr(); err != nil { + return nil, handler.BadEvidence(err) + } + + return ret, nil +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + evCoRIM, err := transformEvidenceToCorim(evidence) + if err != nil { + return nil, handler.BadEvidence(err) + } + + return common.ToMapViaJSON(evCoRIM) +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + taCert, err := getCertFromTrustAnchors(trustAnchors) + if err != nil { + return err + } + + tsm, err := parseEvidence(evidence) + if err != nil { + return handler.BadEvidence(err) + } + + certChain, err := parseCertChainFromTSMReport(tsm) + if err != nil { + return handler.BadEvidence(err) + } + + if err := validateCertChain(certChain); err != nil { + return handler.BadEvidence(err) + } + + if !bytes.Equal(certChain.GetArkCert(), taCert) { + return handler.BadEvidence(ErrTAMismatch) + } + + return nil +} + +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + appraisal := result.Submods[Descriptor.Name] + + appraisal.TrustVector.Hardware = ear.UnsafeHardwareClaim + appraisal.TrustVector.RuntimeOpaque = ear.VisibleMemoryRuntimeClaim + + evMeasurements, err := transformClaimsToMeasurementsMap(claims) + if err != nil { + return result, handler.BadEvidence(err) + } + + matched := false + for i, endorsement := range endorsements { + o.logger.Debugf("attempting to match endorsement %d...", i) + refMeasurements, err := transformValueTripleToMeasurementsMap(endorsement) + if err != nil { + return result, err + } + + if tryMatchEvidence(o.logger, evMeasurements, refMeasurements) { + matched = true + break + } + } + + if matched { + o.logger.Debug("success!") + appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim + appraisal.TrustVector.RuntimeOpaque = ear.EncryptedMemoryRuntimeClaim + } else { + o.logger.Debug("failed to match evidence to reference values!") + } + + appraisal.UpdateStatusFromTrustVector() + appraisal.VeraisonAnnotatedEvidence = &claims + + return result, nil +} + +func parseEvidence(evidence *appraisal.Evidence) (*tokens.TSMReport, error) { + var ( + err error + tsm = new(tokens.TSMReport) + cmwCollection cmw.CMW + ) + + switch evidence.MediaType { + case EvidenceMediaTypeTSMCbor: + err = tsm.FromCBOR(evidence.Data) + if err != nil { + return nil, err + } + case EvidenceMediaTypeTSMJson: + err = tsm.FromJSON(evidence.Data) + if err != nil { + return nil, err + } + case EvidenceMediaTypeRATSd: + eat := make(map[string]any) + + err = json.Unmarshal(evidence.Data, &eat) + if err != nil { + return nil, err + } + + cmwBase64, ok := eat["cmw"].(string) + if !ok { + return nil, handler.BadEvidence(ErrMissingCMW) + } + + cmwJson, err := base64.StdEncoding.DecodeString(cmwBase64) + if err != nil { + return nil, err + } + + err = cmwCollection.UnmarshalJSON(cmwJson) + if err != nil { + return nil, err + } + + cmwMonad, err := cmwCollection.GetCollectionItem("tsm-report") + if err != nil { + return nil, err + } + + cmwType, err := cmwMonad.GetMonadType() + if err != nil { + return nil, err + } + if cmwType != EvidenceMediaTypeTSMJson { + return nil, fmt.Errorf("unexpected CMW type: %s", cmwType) + } + cmwValue, err := cmwMonad.GetMonadValue() + if err != nil { + return nil, err + } + + err = tsm.FromJSON(cmwValue) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unexpected media type: %s", evidence.MediaType) + } + + return tsm, nil +} + +func readCert(cert []byte) ([]byte, error) { + if len(cert) == 0 { + return nil, errors.New("empty certificate") + } + + block, _ := pem.Decode(cert) + if block == nil || block.Type != "CERTIFICATE" { + return nil, ErrCertificateReadFailure + } + return block.Bytes, nil +} + +func parseCertChainFromTSMReport(tsm *tokens.TSMReport) (*sevsnp.CertificateChain, error) { + var certTable abi.CertTable + + if len(tsm.AuxBlob) == 0 { + return nil, ErrMissingCertChain + } + + if err := certTable.Unmarshal(tsm.AuxBlob); err != nil { + return nil, err + } + + return certTable.Proto(), nil +} + +func transformClaimsToCorim(claims map[string]any) (*corim.UnsignedCorim, error) { + claimsJSON, err := json.Marshal(claims) + if err != nil { + return nil, err + } + + var ret corim.UnsignedCorim + if err := ret.FromJSON(claimsJSON); err != nil { + return nil, err + } + + return &ret, nil +} + +func transformEvidenceToComid(evidence *appraisal.Evidence) (*comid.Comid, error) { + tsm, err := parseEvidence(evidence) + if err != nil { + return nil, err + } + + reportProto, err := abi.ReportToProto(tsm.OutBlob) + if err != nil { + return nil, err + } + + evComid, err := sevsnpParser.ReportToComid(reportProto, 0) + if err != nil { + return nil, err + } + + err = evComid.Valid() + if err != nil { + return nil, err + } + + return evComid, err +} + +func transformEvidenceToCorim(evidence *appraisal.Evidence) (*corim.UnsignedCorim, error) { + evComid, err := transformEvidenceToComid(evidence) + if err != nil { + return nil, err + } + + evCorim := corim.UnsignedCorim{} + evCorim.SetProfile(EndorsementMediaTypeRV) + evCorim.AddComid(evComid) + + return &evCorim, nil +} + +func getCertFromTrustAnchors(trustAnchors []*comid.KeyTriple) ([]byte, error) { + vk, err := common.ExtractOneVerifKey(trustAnchors) + if err != nil { + return nil, err + } + + if vk.Type() != comid.PKIXBase64CertType { + return nil, fmt.Errorf("wrong trust anchor: expected %s, found %s", + comid.PKIXBase64CertType, vk.Type()) + } + + return []byte(vk.String()), nil +} + +func validateCertChain(certChain *sevsnp.CertificateChain) error { + if len(certChain.GetArkCert()) == 0 { + return handler.BadEvidence(ErrNoARK) + } + + if len(certChain.GetAskCert()) == 0 { + return handler.BadEvidence(ErrNoASK) + } + + if len(certChain.GetVcekCert()) == 0 && len(certChain.GetVlekCert()) == 0 { + return handler.BadEvidence(ErrNoVEK) + } + + return nil +} + +func transformClaimsToMeasurementsMap(claims map[string]any) (map[uint64]comid.Measurement, error) { + evCorim, err := transformClaimsToCorim(claims) + if err != nil { + return nil, handler.BadEvidence(err) + } + + vtIter, iterErr := evCorim.IterRefVals() + valueTriples := slices.Collect(vtIter) + if err := iterErr(); err != nil { + return nil, err + } + + if numValueTriples := len(valueTriples); numValueTriples != 1 { + return nil, fmt.Errorf("expected exactly one triple in evidence; found %d", numValueTriples) + } + + return transformValueTripleToMeasurementsMap(valueTriples[0]) +} + +func transformValueTripleToMeasurementsMap(vt *comid.ValueTriple) (map[uint64]comid.Measurement, error) { + ret := make(map[uint64]comid.Measurement) + + for _, measurement := range vt.Measurements.Values { + key, err := measurement.Key.GetKeyUint() + if err != nil { + return nil, err + } + + ret[key] = measurement + } + + return ret, nil +} + +func tryMatchEvidence( + logger *zap.SugaredLogger, + evMeasurements, refMeasurements map[uint64]comid.Measurement, +) bool { + for key, refMeasurement := range refMeasurements { + // We can skip validating certain claims for the following reasons: + // - POLICY ToDo: Do we need to test individual policy features? + // - CURRENT_TCB is informational only. It's best handled by policy + // - PLATFORM_INFO ToDO: Do we need to test individual platform features? + // - REPORT_DATA is a nonce supplied by user for freshness. It's used + // for freshness verification, and verified as part of + // evidence integrity check (session nonce check). + // - REPORT_ID is ephemeral, so we can't use it for verification. + // - REPORT_ID_MA is also ephemeral, used for migration + // - CHIP_ID is unique to an specific attester, but reference values could be used more generally + // - Current Version (CURRENT_MAJOR/MINOR/BUILD) should already be part of REPORTED_TCB. + // ToDo: It is a good idea to test it anyway, but the Version type only tests for + // equality, and this would trigger spurious failures + // - COMMITTED_TCB is informational, used by the host to advance REPORTED_TCB + if key == mKeyPolicy || + key == mKeyCurrentTcb || + key == mKeyPlatformInfo || + key == mKeyReportData || + key == mKeyReportID || + key == mKeyReportIDMA || + key == mKeyChipID || + key == mKeyCommittedTcb || + key == mKeyCurrentVersion || + key == mKeyCommittedVersion { + continue + } + + evMeasurement, ok := evMeasurements[key] + if !ok { + logger.Debugf("key %d not in evidence", key) + return false + } + + switch key { + case mKeyReportedTcb: + if !compareTcb(logger, refMeasurement, evMeasurement) { + logger.Debugf("reported TCB (key %d) failed to match", mKeyReportedTcb) + return false + } + case mKeyLaunchTcb: + evReportedTcb, ok := evMeasurements[mKeyReportedTcb] + if !ok { + logger.Debugf("key %d not in evidence", mKeyReportedTcb) + return false + } + + if !compareTcb(logger, refMeasurement, evReportedTcb) { + // TODO: Is this a failure condition? + log.Debug("TEE launched with older TCB version") + } + default: + if !compareMeasurements(logger, refMeasurement, evMeasurement) { + logger.Debugf("MKey %d does not match reference", key) + return false + } + } + + } + + return true +} + +func compareTcb(logger *zap.SugaredLogger, refM comid.Measurement, evM comid.Measurement) bool { + if refM.Val.SVN == nil { + logger.Debug("reference doesn't have SVN") + return false + } + + if evM.Val.SVN == nil { + logger.Debug("evidence doesn't have SVN") + return false + } + + refTcbParts, err := transformSVNtoTCB(*refM.Val.SVN) + if err != nil { + logger.Debugf("could not transform reference SVN to TCB parts: %v", err) + return false + } + + evTcbParts, err := transformSVNtoTCB(*evM.Val.SVN) + if err != nil { + logger.Debugf("could not transform evidence SVN to TCB parts: %v", err) + return false + } + + if evTcbParts.BlSpl < refTcbParts.BlSpl || + evTcbParts.SnpSpl < refTcbParts.SnpSpl || + evTcbParts.TeeSpl < refTcbParts.TeeSpl || + evTcbParts.UcodeSpl < refTcbParts.UcodeSpl { + return false + } + + return true +} + +// transformSVNtoTCB extracts TCB from the supplied SVN. SEV-SNP's TCB_VERSION +// is a composite version; it's bitfield consisting of SVNs from various firmware components +func transformSVNtoTCB(svn comid.SVN) (*kds.TCBParts, error) { + var ( + tcbVersion uint64 + err error + tcbParts kds.TCBParts + ) + + // ToDo: following is a circuitous way to obtain the 64-bit TCB integer value + // from SVN. Consider updating the SVN type to return a 64-bit value + switch v := svn.Value.(type) { + case *comid.TaggedSVN: + tcbString := v.String() + tcbVersion, err = strconv.ParseUint(tcbString, 10, 64) + case *comid.TaggedMinSVN: + tcbString := v.String() + tcbVersion, err = strconv.ParseUint(tcbString, 10, 64) + default: + err = fmt.Errorf("unsupported SVN type: %v", reflect.TypeOf(svn.Value)) + } + + if err != nil { + return nil, err + } + + tcbParts = kds.DecomposeTCBVersion(kds.TCBVersion(tcbVersion)) + + return &tcbParts, nil +} + +// compareMeasurements checks if two given comid.Measurement variables are equal. +func compareMeasurements(logger *zap.SugaredLogger, refM comid.Measurement, evM comid.Measurement) bool { + // RawValue comparison + if refM.Val.RawValue != nil { + if evM.Val.RawValue == nil { + return false + } + + refDigest, _ := refM.Val.RawValue.GetBytes() + return evM.Val.RawValue.CompareAgainstReference(refDigest, nil) + } + + // Digests comparison + if refM.Val.Digests != nil { + if evM.Val.Digests == nil { + return false + } + + return evM.Val.Digests.CompareAgainstReference(*refM.Val.Digests) + } + + // SVN comparison + if refM.Val.SVN != nil { + if evM.Val.SVN == nil { + logger.Debug("evidence doesn't have SVN") + return false + } + + if c, ok := evM.Val.SVN.Value.(*comid.TaggedSVN); ok { + if r, ok := refM.Val.SVN.Value.(*comid.TaggedSVN); ok { + return c.CompareAgainstRefSVN(*r) + } else if r, ok := refM.Val.SVN.Value.(*comid.TaggedMinSVN); ok { + return c.CompareAgainstRefMinSVN(*r) + } else { + logger.Debug("unknown refVal SVN type") + return false + } + } else if c, ok := evM.Val.SVN.Value.(*comid.TaggedMinSVN); ok { + if r, ok := refM.Val.SVN.Value.(*comid.TaggedMinSVN); ok { + return c.Equal(*r) + } + logger.Debug("can't compare TaggedMinSVN against TaggedSVN") + return false + } else { + logger.Debug("unknown evidence SVN type") + return false + } + } + + return true +} diff --git a/scheme/sevsnp/store_handler.go b/scheme/sevsnp/store_handler.go deleted file mode 100644 index e30c0960..00000000 --- a/scheme/sevsnp/store_handler.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package sevsnp - -import ( - "crypto/x509" - "encoding/hex" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "net/url" - - "github.com/google/go-sev-guest/proto/sevsnp" - "github.com/veraison/corim/comid" - "github.com/veraison/ratsd/tokens" - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -var ( - ErrMissingMeasurement = errors.New("measurement not found") - ErrARKDecodeFailure = errors.New("failed to decode ARK") - ErrUnsupportedMultipleEvidence = errors.New("unable to process multiple evidence in a single request") -) - -// StoreHandler implements the IStoreHandler interface handler for SEVSNP scheme -type StoreHandler struct{} - -// GetName returns the name of this StoreHandler instance -func (s StoreHandler) GetName() string { - return fmt.Sprintf("%s-store-handler", SchemeName) -} - -// GetAttestationScheme returns the attestation scheme -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -// GetSupportedMediaTypes returns the supported media types; no-op for SEVSNP -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -// getRefValKey helper to compute RefVal key from CoMID value triple -func getRefValKey(rv comid.ValueTriple, tenantID string) (string, error) { - m, err := measurementByUintKey(rv, mKeyMeasurement) - if err != nil { - return "", err - } - - if m == nil { - return "", ErrMissingMeasurement - } - - d := m.Val.Digests - - u := url.URL{ - Scheme: SchemeName, - Host: tenantID, - Path: hex.EncodeToString((*d)[0].HashValue), - } - - return u.String(), nil -} - -// SynthKeysFromRefValue constructs SEV-SNP reference value of the form -// "SEVSNP:///". The measurement -// is unique to an attester instance and, as such, is -// the best candidate to use as the key. -func (s StoreHandler) SynthKeysFromRefValue( - tenantID string, - refValue *handler.Endorsement, -) ([]string, error) { - var rv comid.ValueTriple - - err := json.Unmarshal(refValue.Attributes, &rv) - if err != nil { - return nil, err - } - - refValKey, err := getRefValKey(rv, tenantID) - if err != nil { - return nil, err - } - - return []string{refValKey}, nil -} - -// SynthKeysFromTrustAnchor constructs the SEV-SNP Trust Anchor key. The -// key format is "SEVSNP://". For example, "SEV-SNP://ARK-Milan" -// -// AMD's Root Key (ARK) is the only Trust Anchor for SEV-SNP. -// -// The attester supplies all the keys in the certificate chain -// for verification. During verification, the scheme must ensure that -// the ARK in the evidence matches the provisioned Trust Anchor. -func (s StoreHandler) SynthKeysFromTrustAnchor(_ string, ta *handler.Endorsement) ([]string, error) { - var avk comid.KeyTriple - - err := json.Unmarshal(ta.Attributes, &avk) - if err != nil { - return nil, err - } - - ark := avk.VerifKeys[0] - - keyBlock, _ := pem.Decode([]byte(ark.String())) - if keyBlock == nil || keyBlock.Type != "CERTIFICATE" { - return nil, ErrARKDecodeFailure - } - - cert, err := x509.ParseCertificate(keyBlock.Bytes) - if err != nil { - return nil, err - } - - u := url.URL{ - Scheme: SchemeName, - Path: cert.Issuer.CommonName, - } - - return []string{u.String()}, nil -} - -// GetTrustAnchorIDs gets the TA ID from evidence -// -// "auxblob" in the TSM report contains a certificate -// table. Extract ARK from it and construct the TA key. -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - var ( - tsm *tokens.TSMReport - certChain *sevsnp.CertificateChain - ark []byte - cert *x509.Certificate - err error - ) - - if tsm, err = parseAttestationToken(token); err != nil { - return nil, err - } - - if certChain, err = parseCertificateChainFromEvidence(tsm); err != nil { - return nil, err - } - - if ark, err = readCert(certChain.GetArkCert()); err != nil { - return nil, fmt.Errorf("can't read ARK to compose TA ID: %w", err) - } - - if cert, err = x509.ParseCertificate(ark); err != nil { - return nil, err - } - - u := url.URL{ - Scheme: SchemeName, - Path: cert.Issuer.CommonName, - } - - return []string{u.String()}, nil -} - -// GetRefValueIDs gets the refval key from the claims set. Looks up -// "measurement" using its MKey (641) and construct the refval key. -// -// Reference value key for SEV-SNP is of the form -// "SEVSNP:///", as explained -// in SynthKeysFromRefValue. -func (s StoreHandler) GetRefValueIDs( - tenantID string, - _ []string, - claims map[string]interface{}, -) ([]string, error) { - claimsJson, err := json.Marshal(claims) - if err != nil { - return nil, err - } - - extractedComid, err := comidFromJson(claimsJson) - if err != nil { - return nil, err - } - - if len(extractedComid.Triples.ReferenceValues.Values) > 1 { - return nil, ErrUnsupportedMultipleEvidence - } - - refValKey, err := getRefValKey(extractedComid.Triples.ReferenceValues.Values[0], tenantID) - if err != nil { - return nil, err - } - - return []string{refValKey}, nil -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - return []string{"TODO"}, nil -} diff --git a/scheme/sevsnp/store_handler_test.go b/scheme/sevsnp/store_handler_test.go deleted file mode 100644 index 44faa199..00000000 --- a/scheme/sevsnp/store_handler_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package sevsnp - -import ( - "encoding/json" - "github.com/veraison/services/proto" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/veraison/services/handler" -) - -func Test_SynthKeysFromRefValue_ok(t *testing.T) { - var e handler.Endorsement - - endorsementsBytes, err := os.ReadFile("test/refval-endorsement.json") - require.NoError(t, err) - - err = json.Unmarshal(endorsementsBytes, &e) - require.NoError(t, err) - expectedKey := "SEVSNP://0/7699e6ac12ccdfd1dfac70e649ce1f046cb2afbb003438f4cdddfe2ccbe182fa5ffbe8dcdb930454324e10c52c788980" - - scheme := &StoreHandler{} - keys, err := scheme.SynthKeysFromRefValue("0", &e) - require.NoError(t, err) - assert.Equal(t, expectedKey, keys[0]) - -} - -func Test_SynthKeysFromTrustAnchor_ok(t *testing.T) { - var e handler.Endorsement - - endorsementsBytes, err := os.ReadFile("test/ta-endorsement.json") - require.NoError(t, err) - - err = json.Unmarshal(endorsementsBytes, &e) - require.NoError(t, err) - - expectedKey := "SEVSNP://ARK-Genoa" - - scheme := &StoreHandler{} - keys, err := scheme.SynthKeysFromTrustAnchor("0", &e) - require.NoError(t, err) - assert.Equal(t, expectedKey, keys[0]) - -} - -func Test_GetTrustAnchorIDs_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/sevsnp-ratsd-token") - require.NoError(t, err) - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: EvidenceMediaTypeRATSd, - Nonce: testNonce, - } - - expectedTaID := "SEVSNP://ARK-Genoa" - - handler := &StoreHandler{} - - taIDs, err := handler.GetTrustAnchorIDs(&token) - require.NoError(t, err) - assert.Equal(t, 1, len(taIDs)) - assert.Equal(t, expectedTaID, taIDs[0]) -} - -func Test_GetRefValueIDs_ok(t *testing.T) { - tokenBytes, err := os.ReadFile("test/sevsnp-ratsd-token") - require.NoError(t, err) - - taEndValBytes, err := os.ReadFile("test/ta-endorsement.json") - require.NoError(t, err) - - handler := &EvidenceHandler{} - - token := proto.AttestationToken{ - TenantId: "0", - Data: tokenBytes, - MediaType: EvidenceMediaTypeRATSd, - Nonce: testNonce, - } - ta := string(taEndValBytes) - claims, err := handler.ExtractClaims(&token, []string{ta}) - require.NoError(t, err) - - expectedRefvalIDs := []string{"SEVSNP://0/7699e6ac12ccdfd1dfac70e649ce1f046cb2afbb003438f4cdddfe2ccbe182fa5ffbe8dcdb930454324e10c52c788980"} - - scheme := &StoreHandler{} - refvalIDs, err := scheme.GetRefValueIDs("0", nil, claims) - require.NoError(t, err) - assert.Equal(t, expectedRefvalIDs, refvalIDs) -} diff --git a/scheme/sevsnp/test/corim/compile-endorsements.sh b/scheme/sevsnp/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..5afd2773 --- /dev/null +++ b/scheme/sevsnp/test/corim/compile-endorsements.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p sevsnp "$THIS_DIR"/corim-*.cbor + diff --git a/scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-key.cbor b/scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-key.cbor new file mode 100644 index 0000000000000000000000000000000000000000..7cba40ece38d984a60dc4930576e49820f2e5ba6 GIT binary patch literal 237 zcmcb~_;oQug{lD*=z?enVQOk=24=zJOc@(*GX9E~x|ks~HBZ;wiE$xAz_-Y&0%kM3 zgXSKyTyQsua|X*ohQ_8v3=0`<DDKTZ!ZNV86 zY&T>?*T>)5`$gAxW#fi>L9(*3v0W1=`ny2gT#JG?l;9KNX0kaw2 zL358;F1VY-IfG>(Lu1n-hJ_3_@;$ZL7+DzSR4_9#-efX}aHtk-Iq6g7l$f&Vw&08j zwi_~{>*H_j{i5r;vT?(`AX(Yi*sh6_wRa!fXdfH1&ULwgTlmeD7i0pCn5OfyCM})L z-MEl(A?W?Wb(oOqr$(FTPx8@mmfrh8*J3Imx zPWbrYdew2@|->=Jl&m7)%-~N&BKYe-s@8Ea8 z|J(b|?@sUjC&*ua^AF_LpTGO`m(TA$zn?)mN0%f^Kj>9*>pyVWTqW7~>C3NP9>4wP z$5(;8C>tMG-g0C?W`V=MX%StP#b9Gu2-N~CG6aRpfdT-X4@B0!inbh+oXJDB2Kye+ z3ugvOAcr#WT@C`7MWD%+5(gq!G}p4JL}tMtFpHlVKJBX40J^F_1MpCn##P{ejljb2 zAQ*KP^QMq!r_lEvk-xv_=D4tCz5%^_Ye?yqx$woCBaH)hA@0&4?z}eX zo~doT_B`6x6iS`-JpHFNNOTrA%J^cHGH;B*St)-~gJ)Y5&UE-(huE6~wpe`Aw}`;s z*GTA_h2yt%($R$_dc-roHraSvhv3Z^EQ?}#il(_~8+T0kY&$F0!1&fR|R(fiXB!pqSn&H3Zd&lV^&hN(O1p!(tFn zrCNLejt-iixpD&-K9E|II4Gs1bz1VhcWHvfRoy)R&F;kP?&?_^XsloF^e!qNh}3Icf@;@M9EX?wiommHrf$$!gU9|&_*y+~Gg;3G#MFFKth&5Hq zgHj%wRATb#W^$LV1%xf+3d$x}CmI{#Ggc>;kE44rgg$Az#wuG91*W?XM#dbY3tl@Y zUp<_cfgQRFczG~cI+q+9A4OUqdSsPED|KM=Xs1hYYtD)oREv1C=q9SJGi4aGSstN& z4eBJmHT(_BX;W95R<`%I>6l-UR?}Iy(2541&90wCx^vWVSewlr`_kA^Zr{-dD>$?R zMHF;)mQMIJxLxLQi$vU}Fl1g1$0m*RCqS{CkgA}#C$ObLDB>6Jj@kAswQh3P|R z=jZ(L!lm`IhRAJM})OKafXG}zKnfy3JB(|kzpPB>QAsHSd@+eKK(ioosdc;d#rhER4P)H=)DEQ}%;LNr-G zg_PS~8A>rDKjVl#7sWB#k4wEfnz@>LGrC2JE7Ws8hDYR*hX*nnCR(rk0@`P#*qb~G zT5Pk%a2)m|2b~nWxHCGEWS*^Qc5(1-P=l?M3p7!Y`?l-#^-3$Muh6F+XV2QECi%@7 z%DRo4k_MitpEH;e_Mnp_#DmkWz~M1%Fq~|zF+#LfJ7>pGnQrf!5Zqv;UW=!fm+Hs$0 z`+5a4SaysJ6 zib|WFEbi`lH6Z9ikLoj7KCMW470&tTDqSn9&$uJ*4Z({t_&8(YLps!3;7!@a zJKJrFn#Um@h`1%jYz3Y(p6n4UB}Gr9+`D3{sYC-2dV%7 literal 0 HcmV?d00001 diff --git a/scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-vendor.cbor b/scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-vendor.cbor new file mode 100644 index 0000000000000000000000000000000000000000..38963091b5fafe1221894a4f6b4c98c5357cb28c GIT binary patch literal 2413 zcmai$$E{WRKaOPYu|RB2zWU6yXzcT2V`OV+J<240}ysrn9& zz=ae3|L%qf<}i6ERirX9D>Ea%s?YEL_4jw{AF;3U;r07v+3%Ud+wR*x;{C_Z@BbbC z_IH1K|LL9i?tg;(_1FJEe)Z}5kAL~}?$dWQu+ncBu{&!c@w zq0(93*MC}rRA+IcO3rpA^TrgOl<8x3rFa~D{6f@YBhM*c@`j%L!WSA8^EJp!V>Ln21hprk=Es#)kDq@8ar#NQ2g=sCJpeX?z(jINWxoIfdHdio04@{Wx|R z3>~7KOb>P9TxW*3D^+(1js%sV_KKur?dgxo$VGQJ-pduOy*25m#1!?_ z;?8{s2uCOslufZ-G&Uq)>|U-ONAGM1L)!JNU3DZ1EN>r9j5Wn)ym3*!ez-3qJN9Sr z@?i4pUU6)46lsANkW~`x%!Tcvo6qI7Jt<;XFXGjv+qk~mDZ`+x>In5q*rds|<*!&l zTe{kIva`R=$Krx?n$E(7Ry6o*cJnOKjiZj^+HTG?RK||-hMqpy;h`HTqNMYaWa5|b zdcId%EaDD@A@}8QY?C-<8NR6{be2k>SmHXIsTs4VwH$0d0BBArDYO=?q%rA&PKiBV z@@d_u1tNhH68l}sg6BYk*m%*UW#L{Y(#A|+N$3+#uLKgm4pPRIRsf+>oQm@cmo?8K z-oPf-r+evi=DiVzU<2kWSS0&7P6f?F7jUnRbZ&SZu1s32P3QPUJAm83&LW})6_!bG zJJ$3)ChYBrGc2n2RT5ZpNH8~zjG8Ez?ped%ze467lFIZAy2vk4_m`lHe8cnqQy1)> z?6*KBcP3;h&g$Ww22<4PQqqEG_#wdazM2iJfM0wqXp%g0) za*h}ZQJnJqv^2Y;Rj7r3N4Hq(GfWp(Sgjznbw=2gw9DR_ZE+W4%_T0n#MiJ zK{o?0-W{DtvdGsgKf8E8s^M12C7PoPOs_BxpqJgjK zryOR4GwLJ>@zC6rI6P)8hLi0jL8!!*BD{u#B8mG{SJh;(SqA`7(%cO=C6}JAj4)CW z+0|Sn&S+ZW!zlLch!d7kE65C!*7aUiE|U8FiB@`sfhWq~$E`aqvTxIDS3>SF!xpkc z*W9jT%B}&L(_WQEAiD#oJvj z1_VRoQ$sGx=89w&;Z&Fx=~CMrpV(Y+!d-E12!5Qy#|aZ3(xKTxf6h1F-L7-oJ`Tl5 zBps2Y+iLPOB4rLq*G;YTJ#+8&m@Rtw5u6%lmd~QSOD20Ra?ym$n7c6pQ+UkXV4H3i z*Mq2lUXVCq|VMx(=n5I>9p8njJUEIiS-L?EASMb;?AE% zp(PdsUGxpNaVV8P{)oIiT6lx|`9tRW^$)kW{2}hMKc_?gCjujOKTPNGLpogR{=;}3 Iin`1H10=ZuasU7T literal 0 HcmV?d00001 diff --git a/scheme/sevsnp/test/corim/corim-sevsnp-valid.cbor b/scheme/sevsnp/test/corim/corim-sevsnp-valid.cbor new file mode 100644 index 0000000000000000000000000000000000000000..53b3cf1b730879605a7c690fbe5997e2347ed4df GIT binary patch literal 3112 zcmai0Ys@268E$t!78!zE5@R+ivLPYCbeFc%+YGRA&zYIdrJZSKI_SE=CD?WZ$i#q80O*|!I~j^CXz&B;L;W=~|= ze;d4TQT13uI{qwv*DKn2$2Lx6jvU>}oXETwu(>_ijqKN#yR+Goy9)iopZw4*KW-*a zH6D5C;$vSr^sw`ZPv7{PC*M5C-+$!c-%6KWdj0jcefjp><4=9}2caZir za#pvM+4#RB=j@D->+r42o^AFk_dWl??diL>GUuM1C0)r@X78?>cd-89(%wIGZ)iOB zp!fN295)VK-ad8DqxYUqew6NCGyKxNCtBZc{gK{tVHSPv);k}%xnC>2di;j@WtkT) zjxT;<+J5TKyPsW?9m$^9b>!%|{lemo*B`j#r>A~(>Vfce_UD&vc#k~vc&3cK`LkF4 zdEh6%Kl=8K@BHcImu}yXQQ@Lz4lHlIc|G|vr&qH7tryJw1a^5|b}v=#xp8x!Vn6ol z`>#CmH2(L$9J}M5N3U52fA&o9yYJK1!Jj)_3Hig@l|WMLf>eif#rubUc%Srz$oSo- z?!3;t`g`BL;K}Hgx4w13KVEA-OT6;ny%Aru|7H9~*Z$(2Yl!E5 z@J#lu^R9jHrb|ve|HhhZN60Jpot+?+G!?-rUR9}Fg=P01PG9z3c+>v^Qwh>z@SoZ1 zBYNI}t@YX5Uhhtae09&O$i|7?M~O?n<{k*Hsg8ihqaCI}<drK9`Ql1KozLuT_}EI?kuVrGY+LBb&%GDAo61#d_|K~;p6wu02KKMaup z+DmwejVZ95jU<5wyW?n6LVI%!rDDd>1%AZFyv(A!+)V_MFDWS|koq=;{2Ls>8ZU`4 zWp5KTNw8Vhd?VESo~Qfi))K0jE^TKE4o~!Y{Mj|od7>yd+C*|#N{9x1&N-_FsVp2R z%9O>!!Zrb6$BL*(=s>BAkf9>lvf_<&AG0O8ho<}U^n~j05Nrp7IOfD2*KBqTPxEmn zm7QQmKscisvLhQ+2cSg&8w2YA!fvF`6etk}Ug_lL_10Wsqp^Z761+#kdKDK)v0lRi z$!Q|_Cfe?aw9_aJ42yzxSkH5Atkhv7=dC{JB%n|XOUuGvTg*d%q>AW2#YN{doOSk0CiD3X)$AnrE06#&NNHeTLr^qV182$q{z zS#?$j6EuB2-<(Et6y}0y5hmq!I~p`&nJ&A0qo=AeUdRW-GK&SS)|t(5bip~^RB53# zBQGrxz2tWJl_Qw69JChpGVgYSvQ39{wJ4C`nCdRrWZuwKeu=S$94a!oeSr%9t%B@ZHrW|UsBr`&TyR&8)yUETXj0s zw%0?bsSM$!D*A32$h6N(xe40Hn>h|RU6dZxMr_DAt+B!2mOB&4iSGflQ@6N0p%;8w zNDu{=eAZdDx)Y%u=$=289IuoIVz)Aga4}LR#gUw++?AXQiO`>b+zL01g+mfri^l3` zfGinWGGsVjdGm=q8}~VS;KuY!!p5pQUDN~t6P*_1r-PBM&BoNMU|}NP7<+7|GMl%o zDdIJG0>&8EgsIr0v`Cv|trafENhb;%pc?2cl13B!jd?1;UQiwD>nJ#k1p8wl*K{@q) z5g4r3hD41N{RLASkGxhgsV_?|TI?jPHW^i#NUdYnM?8Vgq(TkFQCcKGZCLAiQ@qBB zs$!C8V9|7BR-$-RZi!aI>Min#%603bMGy^J$ix~}OJ+F7_>p46PM@SWSL9DoXAB#Yzz{Iwexxd*-Xj-zno%RL*cM?P$c@zq@i0gIdn#z zHg+)3Yw&#&8fYivOC?www99r8wv2J1SQ<|?q^3#Cu;@aRW9W*`HyTyHGv8fuNAXB z2_rlklB+o!Ljv_io3qleqjuTB2wl!sihv`PMtxAmC(2S!@B&d+OHAUg$_X#}(8P`2 z%8M#yvl8OkxUbt1Ps*C@_l7R8%Bp2zWD_xbQ6K1hUDO!IPXDCb)sUe%TPJ3s4{H2a zjw#lNit#efB)lGX%hRaNqOMVYP$^`2_NRlh*5 znCd7Q^yX$l$;oW4j#pJHL^Ti9^kmtlFoZEWCCnYUobTfcuTqfcuGs?pQD@FhXsN74 z(%drXHpD|yR&l7qmMJSqv^kZ#FkjD45p_tg!^W)KugWW{JMWN5zQ~b)_Hy3R;0tX$ z=QY(fE~t(;Vu+qqNUWk>j8v~Tr|V-hM)EPA6s00$>_dl;?T;2pAm95TvwL~@rfOfU e`o>jy;2%H>X!+`B5+2lpnd=`6XMyE<=Dz^IZT@=z literal 0 HcmV?d00001 diff --git a/scheme/sevsnp/test/corim/src/comid-bad-refval-key.json b/scheme/sevsnp/test/corim/src/comid-bad-refval-key.json new file mode 100644 index 00000000..b87b53f3 --- /dev/null +++ b/scheme/sevsnp/test/corim/src/comid-bad-refval-key.json @@ -0,0 +1,38 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "f659d510-3698-4b52-9dc6-39a0dd620998" + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "oid", + "value": "1.3.6.1.4.1.3704.3.1" + } + }, + "instance": { + "type": "bytes", + "value": "exWEyUx6QmFkstsRmJA9sGhbf1/avfQtTamBsN5SHR1dXYqRkyu7wbE/XVyuRacwRlfZqdAcUMQ1Zw8FYqWXCw==" + } + }, + "measurements": [ + { + "key": { + "type": "oid", + "value": "1.3.6.1.4.1.3704.3.1" + }, + "value": { + "svn": { + "type": "exact-value", + "value": 6059311823650291722 + } + } + } + ] + } + ] + } +} diff --git a/scheme/sevsnp/test/corim/src/comid-bad-refval-no-key.json b/scheme/sevsnp/test/corim/src/comid-bad-refval-no-key.json new file mode 100644 index 00000000..ce858e47 --- /dev/null +++ b/scheme/sevsnp/test/corim/src/comid-bad-refval-no-key.json @@ -0,0 +1,34 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "f659d510-3698-4b52-9dc6-39a0dd620998" + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "oid", + "value": "1.3.6.1.4.1.3704.3.1" + } + }, + "instance": { + "type": "bytes", + "value": "exWEyUx6QmFkstsRmJA9sGhbf1/avfQtTamBsN5SHR1dXYqRkyu7wbE/XVyuRacwRlfZqdAcUMQ1Zw8FYqWXCw==" + } + }, + "measurements": [ + { + "value": { + "svn": { + "type": "exact-value", + "value": 6059311823650291722 + } + } + } + ] + } + ] + } +} diff --git a/scheme/sevsnp/test/corim/src/comid-bad-ta-no-model.json b/scheme/sevsnp/test/corim/src/comid-bad-ta-no-model.json new file mode 100644 index 00000000..45b640b9 --- /dev/null +++ b/scheme/sevsnp/test/corim/src/comid-bad-ta-no-model.json @@ -0,0 +1,22 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000A9406E40A" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "Advanced Micro Devices" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert", + "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/sevsnp/test/corim/src/comid-bad-ta-no-vendor.json b/scheme/sevsnp/test/corim/src/comid-bad-ta-no-vendor.json new file mode 100644 index 00000000..540508ca --- /dev/null +++ b/scheme/sevsnp/test/corim/src/comid-bad-ta-no-vendor.json @@ -0,0 +1,22 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000A9406E40A" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "model": "ARK-Genoa" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert", + "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/sevsnp/test/corim/src/comid-sevsnp-refval.json b/scheme/sevsnp/test/corim/src/comid-sevsnp-refval.json new file mode 100644 index 00000000..d3728881 --- /dev/null +++ b/scheme/sevsnp/test/corim/src/comid-sevsnp-refval.json @@ -0,0 +1,241 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "f659d510-3698-4b52-9dc6-39a0dd620998" + }, + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "oid", + "value": "1.3.6.1.4.1.3704.3.1" + } + }, + "instance": { + "type": "bytes", + "value": "exWEyUx6QmFkstsRmJA9sGhbf1/avfQtTamBsN5SHR1dXYqRkyu7wbE/XVyuRacwRlfZqdAcUMQ1Zw8FYqWXCw==" + } + }, + "measurements": [ + { + "key": { + "type": "uint", + "value": 0 + }, + "value": { + "version": { + "value": "2", + "scheme": "decimal" + } + } + }, + { + "key": { + "type": "uint", + "value": 1 + }, + "value": { + "svn": { + "type": "min-value", + "value": 0 + } + } + }, + { + "key": { + "type": "uint", + "value": 2 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AAAAAAADAAA=" + } + } + }, + { + "key": { + "type": "uint", + "value": 3 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + }, + { + "key": { + "type": "uint", + "value": 4 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + }, + { + "key": { + "type": "uint", + "value": 5 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AAAAAA==" + } + } + }, + { + "key": { + "type": "uint", + "value": 6 + }, + "value": { + "svn": { + "type": "exact-value", + "value": 15208092991676743683 + } + } + }, + { + "key": { + "type": "uint", + "value": 7 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "AAAAAAAAAAE=" + } + } + }, + { + "key": { + "type": "uint", + "value": 640 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "MxniVV5Lt61siJ6dZD0iUN+ktKULRB5HWDtakBu8T75P50cGDwEyyomfr4BYNzPknV51HwDVEXcRvHFQwesDxg==" + } + } + }, + { + "key": { + "type": "uint", + "value": 641 + }, + "value": { + "digests": [ + "sha-384;dpnmrBLM39HfrHDmSc4fBGyyr7sANDj0zd3+LMvhgvpf++jc25MEVDJOEMUseImA" + ] + } + }, + { + "key": { + "type": "uint", + "value": 645 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "+dVlIEM4Ii9UaR1XpF90G1dnt9KpKIHEOffumJmktDs=" + } + } + }, + { + "key": { + "type": "uint", + "value": 646 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "//////////////////////////////////////////8=" + } + } + }, + { + "key": { + "type": "uint", + "value": 647 + }, + "value": { + "svn": { + "type": "exact-value", + "value": 6059311823650291722 + } + } + }, + { + "key": { + "type": "uint", + "value": 3328 + }, + "value": { + "raw-value": { + "type": "bytes", + "value": "wqZSi3Nk4H6fXGU6s6oNvXOE+agN/eVMxkPdu4nYk2Ql/4oyVoym7XcQINw5wzzP+ztDysDFAaAJPK1gEt/T7Q==" + } + } + }, + { + "key": { + "type": "uint", + "value": 3329 + }, + "value": { + "svn": { + "type": "exact-value", + "value": 6059311823650291722 + } + } + }, + { + "key": { + "type": "uint", + "value": 3330 + }, + "value": { + "version": { + "value": "1.55.8", + "scheme": "semver" + } + } + }, + { + "key": { + "type": "uint", + "value": 3936 + }, + "value": { + "version": { + "value": "1.55.8", + "scheme": "semver" + } + } + }, + { + "key": { + "type": "uint", + "value": 3968 + }, + "value": { + "svn": { + "type": "exact-value", + "value": 6059311823650291722 + } + } + } + ] + } + ] + } +} diff --git a/scheme/sevsnp/test/corim/src/comid-sevsnp-ta.json b/scheme/sevsnp/test/corim/src/comid-sevsnp-ta.json new file mode 100644 index 00000000..ab6984cb --- /dev/null +++ b/scheme/sevsnp/test/corim/src/comid-sevsnp-ta.json @@ -0,0 +1,23 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000A9406E40A" + }, + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "Advanced Micro Devices", + "model": "ARK-Genoa" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-cert", + "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n" + } + ] + } + ] + } +} diff --git a/scheme/sevsnp/test/corim/src/corim-sevsnp.json b/scheme/sevsnp/test/corim/src/corim-sevsnp.json new file mode 100644 index 00000000..5bc7a054 --- /dev/null +++ b/scheme/sevsnp/test/corim/src/corim-sevsnp.json @@ -0,0 +1,4 @@ +{ + "corim-id": "00000000-0000-0000-5596-000000000000", + "profile": "tag:amd.com,2024:snp-corim-profile" +} diff --git a/scheme/sevsnp/test/corim/src/corims.yaml b/scheme/sevsnp/test/corim/src/corims.yaml new file mode 100644 index 00000000..6294a0dc --- /dev/null +++ b/scheme/sevsnp/test/corim/src/corims.yaml @@ -0,0 +1,15 @@ +corim: corim-sevsnp +outdir: .. +workdir: ../__build +comids: + sevsnp-valid: + - comid-sevsnp-refval + - comid-sevsnp-ta + sevsnp-bad-ta-no-vendor: + - comid-bad-ta-no-vendor + sevsnp-bad-ta-no-model: + - comid-bad-ta-no-model + sevsnp-bad-refval-no-key: + - comid-bad-refval-no-key + sevsnp-bad-refval-key: + - comid-bad-refval-key diff --git a/scheme/sevsnp/test/corim/submit-sevsnp-endorsements.sh b/scheme/sevsnp/test/corim/submit-sevsnp-endorsements.sh new file mode 100755 index 00000000..6a29d453 --- /dev/null +++ b/scheme/sevsnp/test/corim/submit-sevsnp-endorsements.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +cocli corim submit -i --corim-file corim-sevsnp-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="tag:amd.com,2024:snp-corim-profile"' --auth=none + diff --git a/scheme/sevsnp/test/corim/unsignedCorimSevSnp.cbor b/scheme/sevsnp/test/corim/unsignedCorimSevSnp.cbor deleted file mode 100644 index 11aba3916b049a3795c3ad4fb48fc117c9931bbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2761 zcmcb~_;oQu!2hQ?jzN7c(laNR#C~7qoX6O5lkrz1)7-@jsi}Fo?oNyg83MjVUKKE# z;T<&hnB{`INt`oS7BVz8En-;6a3kMSn~jl$aZUv@BjZgbg9wL1%YwR#Qy$dKk4d%K zyoz^kam&vYynmni9CNAX8Gs_p5Rm||2okY~fd!`w zD@4WxqC1dz?aYf9*pY1kx?~Z9BvS)KEW*K9@=<7<_x80p9rNa<*eV6w zU$SK>w~L&6gmu&e={^4Y{GYqC@iQ8o>YTs6A;R4F$=tY7d4{Wk<$`+(0}j4sJ_a(Z zk#QkYV-tIX0r#2K-QO!$A31jT^CpeBPH~Y}GbNAthbT^ZI(yENd9{fXl~#V5mb%D! z?xF{+DKdBKK$=^jE>ZY-HC4gcLPF`|$dTkvz$OTc z0$?&g=*CQF-eb>B#iw7pBDpY@*bl&S` zOhuJv)|#ai&O6S9zCT{^c*DIM&d=>ki5KNPE`k!$XcC2%C74Mx>Bz4}%~IFtb46E# z8niS_9!;W@CsA`o4)1f5jdV%{ukL-)w>R7M|KsnDrP~|7sej7Otg12Frnv5JwZ^}j z9*jO3xy{r0Mw2MsQnc;GyKQ21e(DozQVR}WzcOhwiBg_KJ*@Ht8K1tiS*vBld++M6 zH4`rS7yNbd(ufXE(bM~`n*OTtOIw|a$X(z6Sxub6@nWM%6e)=^S16SvrduWErsyT- d=js?47@1lX=N0HC=NDz>>J}8`r)B1(0sxfX^qBwv diff --git a/scheme/sevsnp/test/sevsnp-ratsd-token b/scheme/sevsnp/test/evidence/sevsnp-ratsd-token similarity index 100% rename from scheme/sevsnp/test/sevsnp-ratsd-token rename to scheme/sevsnp/test/evidence/sevsnp-ratsd-token diff --git a/scheme/sevsnp/test/sevsnp-tsm-report.cbor b/scheme/sevsnp/test/evidence/sevsnp-tsm-report.cbor old mode 100755 new mode 100644 similarity index 100% rename from scheme/sevsnp/test/sevsnp-tsm-report.cbor rename to scheme/sevsnp/test/evidence/sevsnp-tsm-report.cbor diff --git a/scheme/sevsnp/test/sevsnp-tsm-report.json b/scheme/sevsnp/test/evidence/sevsnp-tsm-report.json similarity index 100% rename from scheme/sevsnp/test/sevsnp-tsm-report.json rename to scheme/sevsnp/test/evidence/sevsnp-tsm-report.json diff --git a/scheme/sevsnp/test/evidence/submit-sevsnp-evidence.sh b/scheme/sevsnp/test/evidence/submit-sevsnp-evidence.sh new file mode 100755 index 00000000..6f1a205e --- /dev/null +++ b/scheme/sevsnp/test/evidence/submit-sevsnp-evidence.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +EVIDENCE_FILE=${1:-$THIS_DIR/sevsnp-tsm-report.cbor} +case ${EVIDENCE_FILE##*.} in + cbor) + EVIDENCE_CONTENT_TYPE='application/vnd.veraison.tsm-report+cbor' + ;; + json) + EVIDENCE_CONTENT_TYPE='application/vnd.veraison.configfs-tsm+json' + ;; + *) + EVIDENCE_CONTENT_TYPE='application/eat+cwt; eat_profile="tag:github.com,2025:veraison/ratsd/cmw"' + ;; +esac + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession?nonce=byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA== 2>/dev/null | grep "location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H "content-type: $EVIDENCE_CONTENT_TYPE" --data-binary @"$EVIDENCE_FILE" https://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/sevsnp/test/refval-endorsement.json b/scheme/sevsnp/test/refval-endorsement.json deleted file mode 100644 index aba54a1e..00000000 --- a/scheme/sevsnp/test/refval-endorsement.json +++ /dev/null @@ -1,272 +0,0 @@ -{ - "scheme": "SEVSNP", - "type": "reference value", - "subType": "measurements", - "attributes": { - "environment": { - "class": { - "id": { - "type": "oid", - "value": "1.3.6.1.4.1.3704.3.1" - } - }, - "instance": { - "type": "bytes", - "value": "wqZSi3Nk4H6fXGU6s6oNvXOE+agN/eVMxkPdu4nYk2Ql/4oyVoym7XcQINw5wzzP+ztDysDFAaAJPK1gEt/T7Q==" - } - }, - "measurements": [ - { - "key": { - "type": "uint", - "value": 0 - }, - "value": { - "version": { - "value": "3", - "scheme": "decimal" - } - } - }, - { - "key": { - "type": "uint", - "value": 1 - }, - "value": { - "svn": { - "type": "min-value", - "value": 0 - } - } - }, - { - "key": { - "type": "uint", - "value": 2 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AAAAAAADAAA=" - } - } - }, - { - "key": { - "type": "uint", - "value": 3 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AAAAAAAAAAAAAAAAAAAAAA==" - } - } - }, - { - "key": { - "type": "uint", - "value": 4 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AAAAAAAAAAAAAAAAAAAAAA==" - } - } - }, - { - "key": { - "type": "uint", - "value": 5 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AAAAAA==" - } - } - }, - { - "key": { - "type": "uint", - "value": 6 - }, - "value": { - "svn": { - "type": "exact-value", - "value": 15787368493747273732 - } - } - }, - { - "key": { - "type": "uint", - "value": 7 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AAAAAAAAACU=" - } - } - }, - { - "key": { - "type": "uint", - "value": 640 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "dRhKhRXGvbFREoFUv7JrFG1zSIoFxY1sEX3wXcjefrNYF2Dx2AOZ7zX9Y+KQIGGOAkeWHY42R3qPWjmwKe6gdQ==" - } - } - }, - { - "key": { - "type": "uint", - "value": 641 - }, - "value": { - "digests": [ - "sha-384;dpnmrBLM39HfrHDmSc4fBGyyr7sANDj0zd3+LMvhgvpf++jc25MEVDJOEMUseImA" - ] - } - }, - { - "key": { - "type": "uint", - "value": 645 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "/+c6C6N5+yXqu2wvt1AbmaZurPkr962gp1ajsWQrXOQ=" - } - } - }, - { - "key": { - "type": "uint", - "value": 646 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "//////////////////////////////////////////8=" - } - } - }, - { - "key": { - "type": "uint", - "value": 647 - }, - "value": { - "svn": { - "type": "exact-value", - "value": 6059311823650291722 - } - } - }, - { - "key": { - "type": "uint", - "value": 648 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "GQ==" - } - } - }, - { - "key": { - "type": "uint", - "value": 649 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "EQ==" - } - } - }, - { - "key": { - "type": "uint", - "value": 650 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AQ==" - } - } - }, - { - "key": { - "type": "uint", - "value": 3328 - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "wqZSi3Nk4H6fXGU6s6oNvXOE+agN/eVMxkPdu4nYk2Ql/4oyVoym7XcQINw5wzzP+ztDysDFAaAJPK1gEt/T7Q==" - } - } - }, - { - "key": { - "type": "uint", - "value": 3329 - }, - "value": { - "svn": { - "type": "exact-value", - "value": 15787368493747273732 - } - } - }, - { - "key": { - "type": "uint", - "value": 3330 - }, - "value": { - "version": { - "value": "1.55.29", - "scheme": "semver" - } - } - }, - { - "key": { - "type": "uint", - "value": 3936 - }, - "value": { - "version": { - "value": "1.55.29", - "scheme": "semver" - } - } - }, - { - "key": { - "type": "uint", - "value": 3968 - }, - "value": { - "svn": { - "type": "exact-value", - "value": 15787368493747273732 - } - } - } - ] - } -} diff --git a/scheme/sevsnp/test/refval-prov.cbor b/scheme/sevsnp/test/refval-prov.cbor deleted file mode 100644 index 4f5ea9c0c9e23bfec0c84a4ea73e418d2c9b1a10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5789 zcmZ3?5TKpU?)PrK*OH!zy2bY&G&?eOL^7Sc$@ptALuzWCuDcWCLWTg>3-L~Jr7k)R zyFN+Q#+hAVS;)}Xw1{CL!;O4TZ8k<0#yJ(tjEpy#3?dv3Eeq-{PI*u_KPJ^`^D5rG z#VtQq@cw=3bIkef?#>&NQ&j(V8HM#Mds{A`aL4kn&H3Nf&ZiC>Wn92%vo=BK{^hq* z7cnpZtz5*AXw1m6h=GxDA<$e+AfJhGAq&t34+aomW&nyXLqr0=B1ps{1{Rz$tPmL& zkn%+gY+%zhq;E@rwFB*AN4AB5L3I&>BvS)KEW)8w!mCyE*xrqSLX9E&H)V_D7JGED z9_`H$to;ys;$Ge62=RoEH<)L>H~pLZXo5mwACvnu**-J(s{Sa;4Vv#3l!6RvWL(J9 z*u)-TzX(O@+V*w1;!OHy&&{srsZXSuV){h?)rR3#Qq-}QzPw1(=z30*`zs0IpKZR zyn>4dCZ{S?f1GsQ>t;+vm1owPr4`OQ&V{}|Uh#Oty&TTZ?M#Umo?S~h3o@IE)$NT*cr>fR@Pd$V2tKmP7my1nt6`lsy7 zsv5IxitGMXYy7+E!RVur+dQ3bG%Zu7Tn;U8InNj3`)1pf(95g0-QPW$mMKrm9#;8+ zj89+Mtkp8&y?6E3nh6*E3;sHJX+(#o=;?h|O@CGSrL9gyPgGL6$y@>-3%;ySVz+`b<(ovR1t=*FAjHGLN*w(`LeW(re(_0vXadC zDR(y|-2T?2zhCkC4jU6IqYaTc_4}&Uo;rC)>xh7k#(Oon%5PI(#Fo{d^GnwF`P zmIDm#WfmqnHg%rii@J4DD^tt zNoslbY-`8RvnE+0RxwIPHty<+v>#2&)Je;E7pfk<-tHtfO+D`MnPtqfqiLD)v|JSs z?bP$=-`!2F_L4`JUEZ?o*;)2^YtCG`r@}DF=iZC#s!6TKl+}Y%JXpG?*Pc1DVl*w2 ula`q)R5MCS3as??6LVAalJj%*jSP%T^o#Qfbd&RoGIMncit^Jkb5a2YG)`*( diff --git a/scheme/sevsnp/test/ta-endorsement-bad.json b/scheme/sevsnp/test/ta-endorsement-bad.json deleted file mode 100644 index 16f685bb..00000000 --- a/scheme/sevsnp/test/ta-endorsement-bad.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "scheme": "SEVSNP", - "type": "trust anchor", - "subType": "", - "attributes": { - "environment": { - "class": { - "vendor": "AMD", - "model": "Milan" - } - }, - "verification-keys": [ - { - "type": "pkix-base64-cert", - "value":"-----BEGIN CERTIFICATE-----\nMIIFQzCCAvegAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAgUA\noRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATAwezEUMBIGA1UECwwL\nRW5naW5lZXJpbmcxCzAJBgNVBAYTAlVTMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEL\nMAkGA1UECAwCQ0ExHzAdBgNVBAoMFkFkdmFuY2VkIE1pY3JvIERldmljZXMxEjAQ\nBgNVBAMMCVNFVi1NaWxhbjAeFw0yNTAxMjcyMzE3MDRaFw0zMjAxMjcyMzE3MDRa\nMHoxFDASBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwL\nU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNy\nbyBEZXZpY2VzMREwDwYDVQQDDAhTRVYtVkNFSzB2MBAGByqGSM49AgEGBSuBBAAi\nA2IABCoUIuBoilHXQKx+9uMHC3j+JjMdzzlVQCshIlhcCQAcpkZb2M9ixLc9ezJg\nrH2u2auDkN4dCDVJXMtrc+4kmK5aZb8GP0EIqbAPv7tFx3ebGdbJWF+d/EH3Yaoi\nlnlFaaOCARcwggETMBAGCSsGAQQBnHgBAQQDAgEAMBcGCSsGAQQBnHgBAgQKFghN\naWxhbi1CMDARBgorBgEEAZx4AQMBBAMCAQQwEQYKKwYBBAGceAEDAgQDAgEAMBEG\nCisGAQQBnHgBAwQEAwIBADARBgorBgEEAZx4AQMFBAMCAQAwEQYKKwYBBAGceAED\nBgQDAgEAMBEGCisGAQQBnHgBAwcEAwIBADARBgorBgEEAZx4AQMDBAMCARgwEgYK\nKwYBBAGceAEDCAQEAgIA2zBNBgkrBgEEAZx4AQQEQMKmUotzZOB+n1xlOrOqDb1z\nhPmoDf3lTMZD3buJ2JNkJf+KMlaMpu13ECDcOcM8z/s7Q8rAxQGgCTytYBLf0+0w\nQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDAN\nBglghkgBZQMEAgIFAKIDAgEwA4ICAQAlLqDsAbNdEYToxSGiuS4hoa66OvHXHla/\nhoeEtwrf91IPPvSdZJwdb6lMfVx7Ez9PXndnRIML0t/N+x5dKlSpjPUea8ETaFvr\nBfCANXO9xAuTZZJQ3KdyjR0p8781CM9Z/YoT0/wiWCqg96xj3WuvC03pJRuQHOhz\n7/KvPOs6YXRU2h/BVd48NkKaQcgv3t4nviTBg6pIYe8omLzCe98MO3OU9bf3iDP3\nYtcLMmojQcV53r+DFGlzxfP5U7n8Qz87GbMhKoVmo+HaACKEDs5gjoMtE85bvuCV\nZw3hNxsqmcZQoFbhE6oZPF9d3/5iz0nTz1WR8QGDsRVA7j04sjYtYnTxqVuTQGbW\n19KB9H52OlT/LWkVy4WBsfeP1PZi/LaneI2bO8muUE0F3fAw85FigzXrJsYYz7gX\nCcsdi5ZZVtKarbpVvKJNgAkJN100WQB4ERQxHu0i5iHsuZKvcGZNBIRneWqcXbtW\nLNa3ME6jV+/Bc8vQFgcGago2bqEmoJo+g81AHD1rqbIya8gVvVC+J0ZbYXtxSZJS\nKyKOEUcKXMcdoow0AsdIF2KVs8/xpiVIgh8MF6Vk1pPxhHx4mIlhgg3t46xKzKKJ\npuyP5wLw1Ji8Ia3VaJvPyP1XFlbzwL71iNEkUI2jkfB6xozmYZsBOVKsJe2PVeNu\nMd3Wy3hVWA==\n-----END CERTIFICATE-----" - } - ] - } -} \ No newline at end of file diff --git a/scheme/sevsnp/test/ta-endorsement.json b/scheme/sevsnp/test/ta-endorsement.json deleted file mode 100644 index 53b7426d..00000000 --- a/scheme/sevsnp/test/ta-endorsement.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "scheme": "SEVSNP", - "type": "trust anchor", - "subType": "", - "attributes": { - "environment": { - "class": { - "vendor": "AMD", - "model": "Genoa" - } - }, - "verification-keys": [ - { - "type": "pkix-base64-cert", - "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n" - } - ] - } -} diff --git a/scheme/sevsnp/test/ta-prov.json b/scheme/sevsnp/test/ta-prov.json deleted file mode 100644 index 84d59d7b..00000000 --- a/scheme/sevsnp/test/ta-prov.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "lang": "en-GB", - "tag-identity": { - "id": "a331c36f-09df-4d2a-9c04-8a64c0805c5d", - "version": 0 - }, - "triples": { - "attester-verification-keys": [ - { - "environment": { - "class": { - "vendor": "AMD", - "model": "Milan" - } - }, - "verification-keys": [ - { - "type": "pkix-base64-cert", - "value": "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n" - } - ] - } - ] - } -} diff --git a/scheme/sevsnp/test_vars.go b/scheme/sevsnp/test_vars.go new file mode 100644 index 00000000..413f58db --- /dev/null +++ b/scheme/sevsnp/test_vars.go @@ -0,0 +1,24 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package sevsnp + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-sevsnp-bad-refval-key.cbor + corimSevsnpBadRefvalKey []byte + + //go:embed test/corim/corim-sevsnp-bad-refval-no-key.cbor + corimSevsnpBadRefvalNoKey []byte + + //go:embed test/corim/corim-sevsnp-bad-ta-no-model.cbor + corimSevsnpBadTaNoModel []byte + + //go:embed test/corim/corim-sevsnp-bad-ta-no-vendor.cbor + corimSevsnpBadTaNoVendor []byte + + //go:embed test/corim/corim-sevsnp-valid.cbor + corimSevsnpValid []byte +) diff --git a/scheme/sevsnp/test_vectors.go b/scheme/sevsnp/test_vectors.go deleted file mode 100644 index bc34edd1..00000000 --- a/scheme/sevsnp/test_vectors.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package sevsnp - -import _ "embed" - -var ( - //go:embed test/corim/unsignedCorimSevSnp.cbor - unsignedCorimSevSnp []byte -) diff --git a/scheme/tpm-enacttrust/corim.go b/scheme/tpm-enacttrust/corim.go new file mode 100644 index 00000000..074a595d --- /dev/null +++ b/scheme/tpm-enacttrust/corim.go @@ -0,0 +1,103 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package tpm_enacttrust + +import ( + "crypto/ecdsa" + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/corim/extensions" + "github.com/veraison/eat" + "github.com/veraison/services/scheme/common" +) + +const ProfileString = "https://enacttrust.com/veraison/1.0.0" + +func validateEnvironment(env *comid.Environment) error { + if env.Instance == nil { + return errors.New("instance not set in environment") + } + + if env.Instance.Type() != comid.UUIDType { + return fmt.Errorf("instance: expected uuid, found %s", env.Instance.Type()) + } + + if env.Class != nil { + return errors.New("class set in environment") + } + + if env.Group != nil { + return errors.New("group set in environment") + } + + return nil +} + +func extractEndorsedDigest(measurements []comid.Measurement) ([]byte, error) { + if measLen := len(measurements); measLen != 1 { + return nil, fmt.Errorf("expected exactly one measurement, found %d", measLen) + } + + mea := measurements[0] + + if mea.Val.Digests == nil { + return nil, errors.New("no digests in measurement") + } + + if digestLen := len(*mea.Val.Digests); digestLen != 1 { + return nil, fmt.Errorf("expected exactly one digest in measurement, found %d", digestLen) + } + + return (*mea.Val.Digests)[0].HashValue, nil +} + +func extractKey(keys []*comid.CryptoKey) (*ecdsa.PublicKey, error) { + keysLen := len(keys) + if keysLen != 1 { + return nil, fmt.Errorf("expected trust anchor to contain exactly one key; found %d", keysLen) + } + + akPub := keys[0] + if err := akPub.Valid(); err != nil { + return nil, fmt.Errorf("could not parse ak-pub: %v", err) + } + + key, err := common.DecodePublicKeyPEM([]byte(akPub.String())) + if err != nil { + return nil, err + } + + ret, ok := key.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("could not extract EC public key; got [%T]: %v", key, err) + } + + return ret, nil +} + +func init() { + profileID, err := eat.NewProfile(ProfileString) + if err != nil { + panic(err) + } + + validator := &common.TriplesValidator{ + EnviromentValidator: validateEnvironment, + MeasurementsValidator: func(measurements []comid.Measurement) error { + _, err := extractEndorsedDigest(measurements) + return err + }, + CryptoKeysValidator: func(keys []*comid.CryptoKey) error { + _, err := extractKey(keys) + return err + }, + } + + extMap := extensions.NewMap().Add(comid.ExtTriples, validator) + if err := corim.RegisterProfile(profileID, extMap); err != nil { + panic(err) + } +} diff --git a/scheme/tpm-enacttrust/corim_test.go b/scheme/tpm-enacttrust/corim_test.go new file mode 100644 index 00000000..1105d209 --- /dev/null +++ b/scheme/tpm-enacttrust/corim_test.go @@ -0,0 +1,55 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package tpm_enacttrust + +import ( + "testing" + + "github.com/veraison/services/scheme/common" +) + +func TestProfile(t *testing.T) { + tcs := []common.CorimTestCase{ + { + Title: "ok", + Input: corimEnacttrustValid, + }, + { + Title: "bad class", + Input: corimEnacttrustBadClass, + Err: "class set in environment", + }, + { + Title: "bad instance", + Input: corimEnacttrustBadInstance, + Err: "instance: expected uuid, found ueid", + }, + { + Title: "bad multiple keys", + Input: corimEnacttrustBadMultipleKeys, + Err: "expected trust anchor to contain exactly one key; found 2", + }, + { + Title: "bad no digest", + Input: corimEnacttrustBadNoDigest, + Err: "no digests in measurement", + }, + { + Title: "bad no instance", + Input: corimEnacttrustBadNoInstance, + Err: "instance not set in environment", + }, + { + Title: "bad multiple measurements", + Input: corimEnacttrustBadMultipleMeasurements, + Err: "expected exactly one measurement, found 2", + }, + { + Title: "bad multiple digests", + Input: corimEnacttrustBadMultipleDigests, + Err: "expected exactly one digest in measurement, found 2", + }, + } + + common.RunCorimTests(t, tcs) +} diff --git a/scheme/tpm-enacttrust/endorsement_handler.go b/scheme/tpm-enacttrust/endorsement_handler.go deleted file mode 100644 index 2127db5b..00000000 --- a/scheme/tpm-enacttrust/endorsement_handler.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "errors" - - "mime" - - "github.com/veraison/services/handler" - "github.com/veraison/services/scheme/common" -) - -type EndorsementHandler struct{} - -func (o EndorsementHandler) Init(params handler.EndorsementHandlerParams) error { - return nil // no-op -} - -func (o EndorsementHandler) Close() error { - return nil // no-op -} - -func (o EndorsementHandler) GetName() string { - return "corim (TPM EnactTrust profile)" -} - -func (o EndorsementHandler) GetAttestationScheme() string { - return SchemeName -} - -func (o EndorsementHandler) GetSupportedMediaTypes() []string { - return EndorsementMediaTypes -} - -func (o EndorsementHandler) Decode(data []byte, mediaType string, caCertPool []byte) (*handler.EndorsementHandlerResponse, error) { - extractor := &Extractor{} - - if mediaType != "" { - mt, _, err := mime.ParseMediaType(mediaType) - if err != nil { - return nil, err - } - - // Use signed decoder for signed CoRIM - if mt == "application/rim+cose" { - return common.SignedCorimDecoder(data, extractor, caCertPool) - } - } - - // Default to unsigned CoRIM decoder - return common.UnsignedCorimDecoder(data, extractor) -} - -func (o EndorsementHandler) CoservRepackage(coservQuery string, resultSet []string) ([]byte, error) { - return nil, errors.New("TPM-EnactTrust CoservRepackage not implemented") -} diff --git a/scheme/tpm-enacttrust/endorsement_handler_test.go b/scheme/tpm-enacttrust/endorsement_handler_test.go deleted file mode 100644 index 418a0f30..00000000 --- a/scheme/tpm-enacttrust/endorsement_handler_test.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDecoder_GetAttestationScheme(t *testing.T) { - d := &EndorsementHandler{} - - expected := SchemeName - - actual := d.GetAttestationScheme() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_GetSupportedMediaTypes(t *testing.T) { - d := &EndorsementHandler{} - - expected := EndorsementMediaTypes - - actual := d.GetSupportedMediaTypes() - - assert.Equal(t, expected, actual) -} - -func TestDecoder_Init(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Init(nil)) -} - -func TestDecoder_Close(t *testing.T) { - d := &EndorsementHandler{} - - assert.Nil(t, d.Close()) -} - -func TestDecoder_Decode_empty_data(t *testing.T) { - d := &EndorsementHandler{} - - emptyData := []byte{} - - expectedErr := `empty data` - - _, err := d.Decode(emptyData, "", nil) - - assert.EqualError(t, err, expectedErr) -} - -func TestDecoder_Decode_OK(t *testing.T) { - tvs := [][]byte{ - unsignedCorimComidTpmEnactTrustAKOne, - unsignedCorimComidTpmEnactTrustGoldenOne, - } - - d := &EndorsementHandler{} - - for _, tv := range tvs { - _, err := d.Decode(tv, "", nil) - assert.NoError(t, err) - } -} - -func TestDecoder_Decode_negative_tests(t *testing.T) { - tvs := []struct { - desc string - input []byte - expectedErr string - }{ - { - desc: "multiple verification keys for an instance", - input: unsignedCorimComidTpmEnactTrustAKMult, - expectedErr: `bad key in CoMID at index 0: expecting exactly one AK public key`, - }, - { - desc: "incorrect instance id in the measurement", - input: unsignedCorimComidTpmEnactTrustBadInst, - expectedErr: `bad software component in CoMID at index 0: could not extract instance attributes: could not extract node-id (UUID) from instance-id`, - }, - { - desc: "no instance id specified in the measurement", - input: unsignedCorimComidTpmEnactTrustNoInst, - expectedErr: `bad software component in CoMID at index 0: could not extract instance attributes: expecting instance in environment`, - }, - { - desc: "multiple digest specified in the measurement", - input: unsignedCorimComidTpmEnactTrustMultDigest, - expectedErr: `bad software component in CoMID at index 0: extracting measurement: expecting exactly one digest`, - }, - { - desc: "multiple measurements in ref value triple", - input: unsignedCorimComidTpmEnactTrustGoldenTwo, - expectedErr: `bad software component in CoMID at index 0: expecting one measurement only`, - }, - { - desc: "no digest specified in the measurement", - input: unsignedCorimComidTpmEnactTrustNoDigest, - expectedErr: `bad software component in CoMID at index 0: extracting measurement: measurement value has no digests`, - }, - { - desc: "incorrect instance id specified in the measurement", - input: unsignedCorimComidTpmEnactTrustAKBadInst, - expectedErr: `bad key in CoMID at index 0: could not extract node id: could not extract node-id (UUID) from instance-id`, - }} - - for _, tv := range tvs { - t.Run(tv.desc, func(t *testing.T) { - d := &EndorsementHandler{} - _, err := d.Decode(tv.input, "", nil) - assert.EqualError(t, err, tv.expectedErr) - }) - } -} diff --git a/scheme/tpm-enacttrust/endorsements.go b/scheme/tpm-enacttrust/endorsements.go deleted file mode 100644 index c2941c16..00000000 --- a/scheme/tpm-enacttrust/endorsements.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2021-2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "encoding/json" - "fmt" -) - -type TaAttr struct { - NodeID string `json:"enacttrust-tpm.node-id"` - Key string `json:"enacttrust.ak-pub"` -} - -type TrustAnchorEndorsement struct { - Scheme string `json:"scheme"` - Type string `json:"type"` - SubType string `json:"sub_type"` - Attr TaAttr `json:"attributes"` -} - -type RefValAttr struct { - NodeID string `json:"enacttrust-tpm.node-id"` - Digest string `json:"enacttrust-tpm.digest"` - AlgId int `json:"enacttrust-tpm.alg-id"` -} - -type RefValEndorsement struct { - Scheme string `json:"scheme"` - Type string `json:"type"` - SubType string `json:"sub_type"` - Attr RefValAttr `json:"attributes"` -} - -type Endorsements struct { - Digest string -} - -func (e *Endorsements) Populate(strings []string) error { - l := len(strings) - - if l != 1 { - return fmt.Errorf("incorrect endorsements number: want 1, got %d", l) - } - - var refval RefValEndorsement - - if err := json.Unmarshal([]byte(strings[0]), &refval); err != nil { - return fmt.Errorf("could not decode reference value: %w", err) - } - - e.Digest = refval.Attr.Digest - - return nil -} diff --git a/scheme/tpm-enacttrust/evidence_handler.go b/scheme/tpm-enacttrust/evidence_handler.go deleted file mode 100644 index 354a4d0f..00000000 --- a/scheme/tpm-enacttrust/evidence_handler.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "crypto/ecdsa" - "encoding/json" - "fmt" - "strings" - - tpm2 "github.com/google/go-tpm/tpm2" - - "github.com/veraison/ear" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" - "github.com/veraison/services/scheme/common" -) - -type EvidenceHandler struct{} - -func (s EvidenceHandler) GetName() string { - return "tpm-enacttrust-evidence-handler" -} - -func (s EvidenceHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s EvidenceHandler) GetSupportedMediaTypes() []string { - return EvidenceMediaTypes -} - -func (s EvidenceHandler) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - supported := false - for _, mt := range EvidenceMediaTypes { - if token.MediaType == mt { - supported = true - break - } - } - - if !supported { - return nil, handler.BadEvidence("wrong media type: expect %q, but found %q", - strings.Join(EvidenceMediaTypes, ", "), - token.MediaType, - ) - } - - var decoded Token - - if err := decoded.Decode(token.Data); err != nil { - return nil, handler.BadEvidence("could not decode token: %w", err) - } - - if decoded.AttestationData.Type != tpm2.TagAttestQuote { - return nil, handler.BadEvidence("wrong TPMS_ATTEST type: want %d, got %d", - tpm2.TagAttestQuote, decoded.AttestationData.Type) - } - - var pcrs []interface{} // nolint:prealloc - for _, pcr := range decoded.AttestationData.AttestedQuoteInfo.PCRSelection.PCRs { - pcrs = append(pcrs, int64(pcr)) - } - - claims := make(map[string]interface{}) - claims["pcr-selection"] = pcrs - claims["hash-algorithm"] = int64(decoded.AttestationData.AttestedQuoteInfo.PCRSelection.Hash) - claims["firmware-version"] = decoded.AttestationData.FirmwareVersion - claims["node-id"] = decoded.NodeId.String() - claims["pcr-digest"] = []byte(decoded.AttestationData.AttestedQuoteInfo.PCRDigest) - - return claims, nil -} - -func (s EvidenceHandler) ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - endorsements []string, -) error { - var decoded Token - - if err := decoded.Decode(token.Data); err != nil { - return handler.BadEvidence("could not decode token: %w", err) - } - - pubKey, err := parseKey(trustAnchors[0]) - if err != nil { - return fmt.Errorf("could not parse trust anchor: %w", err) - } - - if err = decoded.VerifySignature(pubKey); err != nil { - return handler.BadEvidence("could not verify token signature: %w", err) - } - - return nil -} - -func (s EvidenceHandler) AppraiseEvidence( - ec *proto.EvidenceContext, - endorsementStrings []string, -) (*ear.AttestationResult, error) { - result := handler.CreateAttestationResult(SchemeName) - evidence := ec.Evidence.AsMap() - digestValue, ok := evidence["pcr-digest"] - if !ok { - err := handler.BadEvidence( - "evidence does not contain %q entry", - "pcr-digest", - ) - return result, err - } - - evidenceDigest, ok := digestValue.(string) - if !ok { - err := handler.BadEvidence( - "wrong type value %q entry; expected string but found %T", - "pcr-digest", - digestValue, - ) - return result, err - } - - var endorsements Endorsements - if err := endorsements.Populate(endorsementStrings); err != nil { - return result, err - } - - appraisal := result.Submods[SchemeName] - appraisal.VeraisonAnnotatedEvidence = &evidence - - if endorsements.Digest == evidenceDigest { - appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim - *appraisal.Status = ear.TrustTierAffirming - } else { - appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim - *appraisal.Status = ear.TrustTierContraindicated - } - - return result, nil -} - -func parseKey(trustAnchor string) (*ecdsa.PublicKey, error) { - var taEndorsement TrustAnchorEndorsement - - if err := json.Unmarshal([]byte(trustAnchor), &taEndorsement); err != nil { - return nil, fmt.Errorf("could not decode trust anchor: %w", err) - } - - key, err := common.DecodePemSubjectPubKeyInfo([]byte(taEndorsement.Attr.Key)) - if err != nil { - return nil, err - } - - ret, ok := key.(*ecdsa.PublicKey) - if !ok { - return nil, fmt.Errorf("could not extract EC public key; got [%T]: %v", key, err) - } - - return ret, nil -} diff --git a/scheme/tpm-enacttrust/evidence_handler_test.go b/scheme/tpm-enacttrust/evidence_handler_test.go deleted file mode 100644 index 23d9117e..00000000 --- a/scheme/tpm-enacttrust/evidence_handler_test.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "encoding/base64" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/veraison/ear" - "github.com/veraison/services/proto" - "google.golang.org/protobuf/types/known/structpb" -) - -func Test_DecodeAttestationData_ok(t *testing.T) { - data, err := os.ReadFile("test/tokens/basic.token") - require.NoError(t, err) - - var decoded Token - - err = decoded.Decode(data) - require.NoError(t, err) - - assert.Equal(t, uint32(4283712327), decoded.AttestationData.Magic) - assert.Equal(t, uint64(0x7), decoded.AttestationData.FirmwareVersion) -} - -func readPublicKeyBytes(path string) ([]byte, error) { - buf, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - return buf, nil -} - -func Test_ExtractVerifiedClaims_ok(t *testing.T) { - data, err := os.ReadFile("test/tokens/basic.token") - require.NoError(t, err) - - ta := proto.AttestationToken{ - TenantId: "0", - MediaType: "application/vnd.enacttrust.tpm-evidence", - Data: data, - } - - var s EvidenceHandler - - trustAnchorBytes, err := readPublicKeyBytes("test/keys/basic.pem.pub") - require.NoError(t, err) - trustAnchor := base64.StdEncoding.EncodeToString(trustAnchorBytes) - - ev, err := s.ExtractClaims(&ta, []string{trustAnchor}) - require.Nil(t, err) - - expectedPCRDigest := []byte{ - 0x87, 0x42, 0x8f, 0xc5, 0x22, 0x80, 0x3d, 0x31, 0x6, 0x5e, 0x7b, 0xce, - 0x3c, 0xf0, 0x3f, 0xe4, 0x75, 0x9, 0x66, 0x31, 0xe5, 0xe0, 0x7b, 0xbd, - 0x7a, 0xf, 0xde, 0x60, 0xc4, 0xcf, 0x25, 0xc7, - } - - assert.Equal(t, []interface{}{int64(1), int64(2), int64(3), int64(4)}, - ev["pcr-selection"]) - assert.Equal(t, int64(11), ev["hash-algorithm"]) - assert.Equal(t, expectedPCRDigest, ev["pcr-digest"]) - - var sh StoreHandler - - refIDs, err := sh.GetRefValueIDs("0", []string{trustAnchor}, ev) - - assert.NoError(t, err) - assert.Equal(t, 1, len(refIDs)) - assert.Equal(t, "TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1", refIDs[0]) -} - -func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { - data, err := os.ReadFile("test/tokens/basic.token") - require.NoError(t, err) - - ta := proto.AttestationToken{ - TenantId: "0", - MediaType: "application/vnd.enacttrust.tpm-evidence", - Data: data, - } - - var s EvidenceHandler - - trustAnchorBytes, err := os.ReadFile("test/trustanchor.json") - require.NoError(t, err) - tas := string(trustAnchorBytes) - err = s.ValidateEvidenceIntegrity(&ta, []string{tas}, nil) - assert.Nil(t, err) - -} - -func Test_GetAttestation(t *testing.T) { - evStruct, err := structpb.NewStruct(map[string]interface{}{ - "pcr-selection": []interface{}{1, 2, 3, 4}, - "hash-algorithm": int64(11), - "pcr-digest": []byte{ - 0x87, 0x42, 0x8f, 0xc5, 0x22, 0x80, 0x3d, 0x31, 0x6, 0x5e, 0x7b, - 0xce, 0x3c, 0xf0, 0x3f, 0xe4, 0x75, 0x9, 0x66, 0x31, 0xe5, 0xe0, - 0x7b, 0xbd, 0x7a, 0xf, 0xde, 0x60, 0xc4, 0xcf, 0x25, 0xc7, - }, - }) - require.NoError(t, err) - - evidenceContext := &proto.EvidenceContext{ - TenantId: "0", - TrustAnchorIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - ReferenceIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - Evidence: evStruct, - } - - refvalBytes, err := os.ReadFile("test/refval.json") - require.NoError(t, err) - - var scheme EvidenceHandler - - result, err := scheme.AppraiseEvidence(evidenceContext, []string{string(refvalBytes)}) - require.NoError(t, err) - - appraisal := result.Submods["TPM_ENACTTRUST"] - - assert.Equal(t, ear.TrustTierAffirming, *appraisal.Status) - assert.Equal(t, ear.TrustTierAffirming, - appraisal.TrustVector.Executables.GetTier()) -} diff --git a/scheme/tpm-enacttrust/extractor.go b/scheme/tpm-enacttrust/extractor.go deleted file mode 100644 index 376a32a2..00000000 --- a/scheme/tpm-enacttrust/extractor.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/veraison/corim/comid" - "github.com/veraison/services/handler" -) - -type Extractor struct { - Profile string -} - -func (o *Extractor) SetProfile(p string) { - o.Profile = p -} - -func (o Extractor) RefValExtractor(rvs comid.ValueTriples) ([]*handler.Endorsement, error) { - if len(rvs.Values) != 1 { - return nil, fmt.Errorf("expecting one measurement only") - } - - rv := rvs.Values[0] - var instanceAttrs InstanceAttributes - - if err := instanceAttrs.FromEnvironment(rv.Environment); err != nil { - return nil, fmt.Errorf("could not extract instance attributes: %w", err) - } - - if len(rv.Measurements.Values) != 1 { - return nil, fmt.Errorf("expecting one measurement only") - } - - var ( - swComponents []*handler.Endorsement - swCompAttrs SwCompAttributes - measurement comid.Measurement = rv.Measurements.Values[0] - ) - - if err := swCompAttrs.FromMeasurement(measurement); err != nil { - return nil, fmt.Errorf("extracting measurement: %w", err) - } - - swAttrs, err := makeSwAttrs(instanceAttrs, swCompAttrs) - if err != nil { - return nil, fmt.Errorf("failed to create software component attributes: %w", err) - } - - swComponent := handler.Endorsement{ - Scheme: SchemeName, - Type: handler.EndorsementType_REFERENCE_VALUE, - SubType: "enacttrust-tpm.sw-component", - Attributes: swAttrs, - } - - swComponents = append(swComponents, &swComponent) - - if len(swComponents) == 0 { - return nil, fmt.Errorf("no software components found") - } - - return swComponents, nil -} - -func makeSwAttrs(i InstanceAttributes, s SwCompAttributes) (json.RawMessage, error) { - sw := map[string]interface{}{ - "enacttrust-tpm.node-id": i.NodeID, - "enacttrust-tpm.digest": s.Digest, - "enacttrust-tpm.alg-id": s.AlgID, - } - msg, err := json.Marshal(sw) - if err != nil { - return nil, err - } - return msg, nil -} - -func (o Extractor) TaExtractor(avk comid.KeyTriple) (*handler.Endorsement, error) { - var instanceAttrs InstanceAttributes - - if err := instanceAttrs.FromEnvironment(avk.Environment); err != nil { - return nil, fmt.Errorf("could not extract node id: %w", err) - } - - // extract AK pub - if len(avk.VerifKeys) != 1 { - return nil, errors.New("expecting exactly one AK public key") - } - - akPub := avk.VerifKeys[0] - - if _, ok := akPub.Value.(*comid.TaggedPKIXBase64Key); !ok { - return nil, fmt.Errorf("ak-pub does not appear to be a PEM key (%T)", akPub.Value) - } - - if err := akPub.Valid(); err != nil { - return nil, fmt.Errorf("could not parse ak-pub: %v", err) - } - - taAttrs, err := makeTaAttrs(instanceAttrs, akPub) - if err != nil { - return nil, fmt.Errorf("failed to create trust anchor raw public key: %w", err) - } - - ta := &handler.Endorsement{ - Scheme: SchemeName, - Type: handler.EndorsementType_VERIFICATION_KEY, - Attributes: taAttrs, - } - - return ta, nil -} - -func makeTaAttrs(i InstanceAttributes, key *comid.CryptoKey) (json.RawMessage, error) { - attrs := map[string]interface{}{ - "enacttrust-tpm.node-id": i.NodeID, - "enacttrust.ak-pub": key.String(), - } - - msg, err := json.Marshal(attrs) - if err != nil { - return nil, err - } - return msg, nil -} diff --git a/scheme/tpm-enacttrust/instanceattributes.go b/scheme/tpm-enacttrust/instanceattributes.go deleted file mode 100644 index e6492940..00000000 --- a/scheme/tpm-enacttrust/instanceattributes.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2022-2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "fmt" - - "github.com/veraison/corim/comid" -) - -type InstanceAttributes struct { - NodeID string -} - -func (o *InstanceAttributes) FromEnvironment(e comid.Environment) error { - inst := e.Instance - - if inst == nil { - return fmt.Errorf("expecting instance in environment") - } - - nodeID, err := e.Instance.GetUUID() - if err != nil { - return fmt.Errorf("could not extract node-id (UUID) from instance-id") - } - - o.NodeID = nodeID.String() - - return nil -} diff --git a/scheme/tpm-enacttrust/plugin/Makefile b/scheme/tpm-enacttrust/plugin/Makefile index 33a74ffc..b223116e 100644 --- a/scheme/tpm-enacttrust/plugin/Makefile +++ b/scheme/tpm-enacttrust/plugin/Makefile @@ -1,11 +1,11 @@ +# Copyright 2022 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 -ifndef COMBINED_PLUGINS - SUBDIR += endorsement-handler - SUBDIR += evidence-handler - SUBDIR += store-handler -else - SUBDIR += combined -endif +PLUGIN := ../../bin/scheme-tpm-enacttrust.plugin +GOPKG := github.com/veraison/services/scheme/tpm-enacttrust +SRCS := main.go include ../../../mk/common.mk -include ../../../mk/subdir.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk diff --git a/scheme/tpm-enacttrust/plugin/combined/Makefile b/scheme/tpm-enacttrust/plugin/combined/Makefile deleted file mode 100644 index 1ea603dd..00000000 --- a/scheme/tpm-enacttrust/plugin/combined/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2022 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/tpm-enacttrust.plugin -GOPKG := github.com/veraison/services/scheme/tpm-enacttrust -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/tpm-enacttrust/plugin/combined/main.go b/scheme/tpm-enacttrust/plugin/combined/main.go deleted file mode 100644 index e37a08a1..00000000 --- a/scheme/tpm-enacttrust/plugin/combined/main.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/tpm-enacttrust" -) - -func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/tpm-enacttrust/plugin/endorsement-handler/Makefile b/scheme/tpm-enacttrust/plugin/endorsement-handler/Makefile deleted file mode 100644 index d7cd2fa2..00000000 --- a/scheme/tpm-enacttrust/plugin/endorsement-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2022 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/tpm-enacttrust-endorsement-handler.plugin -GOPKG := github.com/veraison/services/scheme/tpm-enacttrust -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/tpm-enacttrust/plugin/evidence-handler/Makefile b/scheme/tpm-enacttrust/plugin/evidence-handler/Makefile deleted file mode 100644 index c99158a4..00000000 --- a/scheme/tpm-enacttrust/plugin/evidence-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2022 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/tpm-enacttrust-evidence-handler.plugin -GOPKG := github.com/veraison/services/scheme/tpm-enacttrust -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/tpm-enacttrust/plugin/evidence-handler/main.go b/scheme/tpm-enacttrust/plugin/evidence-handler/main.go deleted file mode 100644 index 51f494b3..00000000 --- a/scheme/tpm-enacttrust/plugin/evidence-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2021-2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/tpm-enacttrust" -) - -func main() { - handler.RegisterEvidenceHandler(&scheme.EvidenceHandler{}) - plugin.Serve() -} diff --git a/scheme/tpm-enacttrust/plugin/endorsement-handler/main.go b/scheme/tpm-enacttrust/plugin/main.go similarity index 62% rename from scheme/tpm-enacttrust/plugin/endorsement-handler/main.go rename to scheme/tpm-enacttrust/plugin/main.go index 93f53abc..a303188f 100644 --- a/scheme/tpm-enacttrust/plugin/endorsement-handler/main.go +++ b/scheme/tpm-enacttrust/plugin/main.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -9,6 +9,6 @@ import ( ) func main() { - handler.RegisterEndorsementHandler(&scheme.EndorsementHandler{}) + handler.RegisterSchemeImplementation(scheme.Descriptor, &scheme.Implementation{}) plugin.Serve() } diff --git a/scheme/tpm-enacttrust/plugin/store-handler/Makefile b/scheme/tpm-enacttrust/plugin/store-handler/Makefile deleted file mode 100644 index 2bd8a9ee..00000000 --- a/scheme/tpm-enacttrust/plugin/store-handler/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -PLUGIN := ../../../bin/tpm-enacttrust-store-handler.plugin -GOPKG := github.com/veraison/services/scheme/tpm-enacttrust -SRCS := main.go - -include ../../../../mk/common.mk -include ../../../../mk/plugin.mk -include ../../../../mk/lint.mk -include ../../../../mk/test.mk diff --git a/scheme/tpm-enacttrust/plugin/store-handler/main.go b/scheme/tpm-enacttrust/plugin/store-handler/main.go deleted file mode 100644 index 3722f960..00000000 --- a/scheme/tpm-enacttrust/plugin/store-handler/main.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" - scheme "github.com/veraison/services/scheme/tpm-enacttrust" -) - -func main() { - handler.RegisterStoreHandler(&scheme.StoreHandler{}) - plugin.Serve() -} diff --git a/scheme/tpm-enacttrust/scheme.go b/scheme/tpm-enacttrust/scheme.go index 473dfa6a..c6f0fc35 100644 --- a/scheme/tpm-enacttrust/scheme.go +++ b/scheme/tpm-enacttrust/scheme.go @@ -1,18 +1,182 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package tpm_enacttrust -const SchemeName = "TPM_ENACTTRUST" +import ( + "bytes" + "fmt" -var ( - EndorsementMediaTypes = []string{ - // Unsigned CoRIM profiles - `application/corim-unsigned+cbor; profile="http://enacttrust.com/veraison/1.0.0"`, - // Signed CoRIM profiles - `application/rim+cose; profile="http://enacttrust.com/veraison/1.0.0"`, - } + "github.com/google/go-tpm/tpm2" + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/services/handler" + "github.com/veraison/services/vts/appraisal" +) - EvidenceMediaTypes = []string{ +var Descriptor = handler.SchemeDescriptor{ + Name: "TPM_ENACTTRUST", + VersionMajor: 1, + VersionMinor: 0, + CorimProfiles: []string{ + ProfileString, + }, + EvidenceMediaTypes: []string{ "application/vnd.enacttrust.tpm-evidence", + }, +} + +type Implementation struct{} + +func NewImplementation() *Implementation { + return &Implementation{} +} + +func (o *Implementation) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + return extractEnvinromentsFromEvidence(evidence) +} + +func (o *Implementation) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + return extractEnvinromentsFromClaims(claims) +} + +func (o *Implementation) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + var decoded Token + + if err := decoded.Decode(evidence.Data); err != nil { + return nil, handler.BadEvidence("could not decode token: %w", err) } -) + + if decoded.AttestationData.Type != tpm2.TagAttestQuote { + return nil, handler.BadEvidence("wrong TPMS_ATTEST type: want %d, got %d", + tpm2.TagAttestQuote, decoded.AttestationData.Type) + } + + pcrs := make([]int64, 0, len(decoded.AttestationData.AttestedQuoteInfo.PCRSelection.PCRs)) + for _, pcr := range decoded.AttestationData.AttestedQuoteInfo.PCRSelection.PCRs { + pcrs = append(pcrs, int64(pcr)) + } + + claims := make(map[string]any) + claims["pcr-selection"] = pcrs + claims["hash-algorithm"] = int64(decoded.AttestationData.AttestedQuoteInfo.PCRSelection.Hash) + claims["firmware-version"] = decoded.AttestationData.FirmwareVersion + claims["node-id"] = decoded.NodeId.String() + claims["pcr-digest"] = []byte(decoded.AttestationData.AttestedQuoteInfo.PCRDigest) + + return claims, nil +} + +func (o *Implementation) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + var decoded Token + if err := decoded.Decode(evidence.Data); err != nil { + return handler.BadEvidence("could not decode evidence: %w", err) + } + + taLen := len(trustAnchors) + if taLen != 1 { + return fmt.Errorf("expected exactly one trust anchor; found %d", taLen) + } + + pubKey, err := extractKey(trustAnchors[0].VerifKeys) + if err != nil { + return err + } + + if err = decoded.VerifySignature(pubKey); err != nil { + return handler.BadEvidence("could not verify evidence signature: %w", err) + } + + return nil +} + +func (o *Implementation) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + result := handler.CreateAttestationResult(Descriptor.Name) + + evidenceDigest, ok := claims["pcr-digest"] + if !ok { + err := handler.BadEvidence("claims do not contain %q entry", "pcr-digest") + return result, err + } + + evidenceDigestBytes, ok := evidenceDigest.([]byte) + if !ok { + err := handler.BadEvidence("pcr-digest: expected []byte, found %T", evidenceDigest) + return result, err + } + + appraisal := result.Submods[Descriptor.Name] + appraisal.VeraisonAnnotatedEvidence = &claims + + var endorsedDigests [][]byte // nolint:prealloc + for i, triple := range endorsements { + digest, err := extractEndorsedDigest(triple.Measurements.Values) + if err != nil { + return nil, fmt.Errorf("endorsement %d: %w", i, err) + } + + endorsedDigests = append(endorsedDigests, digest) + } + + matched := false + for _, endorsedDigest := range endorsedDigests { + if bytes.Equal(endorsedDigest, evidenceDigestBytes) { + appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim + *appraisal.Status = ear.TrustTierAffirming + + matched = true + break + } + } + + if !matched { + appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim + *appraisal.Status = ear.TrustTierContraindicated + } + + return result, nil +} + +func extractEnvinromentsFromEvidence(evidence *appraisal.Evidence) ([]*comid.Environment, error) { + var decoded Token + + if err := decoded.Decode(evidence.Data); err != nil { + return nil, handler.BadEvidence("could not decode token: %w", err) + } + + return nodeIDToEnvironments(decoded.NodeId) +} + +func extractEnvinromentsFromClaims(claims map[string]any) ([]*comid.Environment, error) { + nodeID, ok := claims["node-id"] + if !ok { + return nil, handler.BadEvidence("no node ID in claims") + } + + return nodeIDToEnvironments(nodeID) +} + +func nodeIDToEnvironments(nodeID any) ([]*comid.Environment, error) { + instance, err := comid.NewUUIDInstance(nodeID) + if err != nil { + return nil, handler.BadEvidence("could not create CoMID instance form node ID: %w", err) + } + + return []*comid.Environment{ + &comid.Environment{Instance: instance}, + }, nil +} diff --git a/scheme/tpm-enacttrust/store_handler.go b/scheme/tpm-enacttrust/store_handler.go deleted file mode 100644 index e0978aaf..00000000 --- a/scheme/tpm-enacttrust/store_handler.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2024-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package tpm_enacttrust - -import ( - "encoding/json" - "fmt" - "net/url" - "strings" - - "github.com/veraison/services/handler" - "github.com/veraison/services/proto" -) - -type StoreHandler struct { -} - -func (s StoreHandler) GetName() string { - return "tpm-enacttrust-store-handler" -} - -func (s StoreHandler) GetAttestationScheme() string { - return SchemeName -} - -func (s StoreHandler) GetSupportedMediaTypes() []string { - return nil -} - -func (s StoreHandler) GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) { - supported := false - for _, mt := range EvidenceMediaTypes { - if token.MediaType == mt { - supported = true - break - } - } - - if !supported { - err := handler.BadEvidence( - "wrong media type: expect %q, but found %q", - strings.Join(EvidenceMediaTypes, ", "), - token.MediaType, - ) - return []string{""}, err - } - - var decoded Token - - if err := decoded.Decode(token.Data); err != nil { - return nil, handler.BadEvidence(err) - } - - return []string{tpmEnactTrustLookupKey(token.TenantId, decoded.NodeId.String())}, nil -} - -func (s StoreHandler) GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, -) ([]string, error) { - nodeID, ok := claims["node-id"].(string) - if !ok { - return nil, fmt.Errorf("invalid node-id value: %v", claims["node-id"]) - } - - return []string{tpmEnactTrustLookupKey(tenantID, nodeID)}, nil -} - -func (s StoreHandler) SynthKeysFromRefValue( - tenantID string, - swComp *handler.Endorsement, -) ([]string, error) { - return synthKeysFromAttrs("software component", tenantID, swComp.Attributes) -} - -func (s StoreHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) { - return synthKeysFromAttrs("trust anchor", tenantID, ta.Attributes) -} - -func synthKeysFromAttrs(scope string, tenantID string, attr json.RawMessage) ([]string, error) { - var ( - nodeID string - err error - ) - - switch scope { - case "software component": - var att RefValAttr - if err = json.Unmarshal(attr, &att); err != nil { - return nil, fmt.Errorf("unable to extract sw component: %w", err) - } - nodeID = att.NodeID - case "trust anchor": - var att TaAttr - if err = json.Unmarshal(attr, &att); err != nil { - return nil, fmt.Errorf("unable to extract trust anchor: %w", err) - } - nodeID = att.NodeID - default: - return nil, fmt.Errorf("invalid scope: %s", scope) - } - - return []string{tpmEnactTrustLookupKey(tenantID, nodeID)}, nil -} - -func tpmEnactTrustLookupKey(tenantID, nodeID string) string { - absPath := []string{nodeID} - - u := url.URL{ - Scheme: SchemeName, - Host: tenantID, - Path: strings.Join(absPath, "/"), - } - - return u.String() -} - -func (s StoreHandler) SynthCoservQueryKeys(tenantID string, query string) ([]string, error) { - return []string{"TODO"}, nil -} diff --git a/scheme/tpm-enacttrust/store_handler_test.go b/scheme/tpm-enacttrust/store_handler_test.go deleted file mode 100644 index dab8a30d..00000000 --- a/scheme/tpm-enacttrust/store_handler_test.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/veraison/services/proto" -) - -func Test_GetTrustAnchorIDs_ok(t *testing.T) { - data, err := os.ReadFile("test/tokens/basic.token") - require.NoError(t, err) - - ta := proto.AttestationToken{ - TenantId: "0", - MediaType: "application/vnd.enacttrust.tpm-evidence", - Data: data, - } - - var s StoreHandler - - taIDs, err := s.GetTrustAnchorIDs(&ta) - require.NoError(t, err) - assert.Equal(t, "TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1", taIDs[0]) -} - -func Test_GetRefValueIDs_ok(t *testing.T) { - raw, err := os.ReadFile("test/tokens/basic.json") - require.NoError(t, err) - - claims := make(map[string]interface{}) - err = json.Unmarshal(raw, &claims) - require.NoError(t, err) - - expectedRefvalIDs := []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"} - - s := StoreHandler{} - - refvalIDs, err := s.GetRefValueIDs("0", nil, claims) - require.NoError(t, err) - assert.Equal(t, expectedRefvalIDs, refvalIDs) -} diff --git a/scheme/tpm-enacttrust/swcompattributes.go b/scheme/tpm-enacttrust/swcompattributes.go deleted file mode 100644 index fce4b3fc..00000000 --- a/scheme/tpm-enacttrust/swcompattributes.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022-2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import ( - "fmt" - - "github.com/veraison/corim/comid" -) - -type SwCompAttributes struct { - AlgID uint64 - Digest []byte -} - -func (o *SwCompAttributes) FromMeasurement(m comid.Measurement) error { - // extract digest and alg-id from mval - d := m.Val.Digests - - if d == nil { - return fmt.Errorf("measurement value has no digests") - } - - if len(*d) != 1 { - return fmt.Errorf("expecting exactly one digest") - } - - o.AlgID = (*d)[0].HashAlgID - o.Digest = (*d)[0].HashValue - - return nil -} diff --git a/scheme/tpm-enacttrust/test/corim/build-test-vectors.sh b/scheme/tpm-enacttrust/test/corim/build-test-vectors.sh deleted file mode 100755 index 9bcf1c8f..00000000 --- a/scheme/tpm-enacttrust/test/corim/build-test-vectors.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# Copyright 2022-2024 Contributors to the Veraison project. -# SPDX-License-Identifier: Apache-2.0 - -set -eu -set -o pipefail - -THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -GEN_CORIM="$THIS_DIR/../../../common/scripts/gen-corim" - -CORIM_TEMPLATE=corimMini - -COMID_TEMPLATES=( - ComidTpmEnactTrustAKOne - ComidTpmEnactTrustGoldenOne - ComidTpmEnactTrustAKMult - ComidTpmEnactTrustBadInst - ComidTpmEnactTrustNoInst - ComidTpmEnactTrustMultDigest - ComidTpmEnactTrustGoldenTwo - ComidTpmEnactTrustNoDigest - ComidTpmEnactTrustAKBadInst -) - -for comid in "${COMID_TEMPLATES[@]}" -do - "$GEN_CORIM" "$THIS_DIR" "$comid" "$CORIM_TEMPLATE" "unsigned" -done - -echo "done" diff --git a/scheme/tpm-enacttrust/test/corim/compile-endorsements.sh b/scheme/tpm-enacttrust/test/corim/compile-endorsements.sh new file mode 100755 index 00000000..eec7b49b --- /dev/null +++ b/scheme/tpm-enacttrust/test/corim/compile-endorsements.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$THIS_DIR/../../../../scripts" +SRC_DIR="$THIS_DIR/src" + +echo "Generating CoRIMs" +"$SCRIPT_DIR/generate-corims" "$SRC_DIR/corims.yaml" + +echo "Generating test_vars.go" +"$SCRIPT_DIR/generate-test-vector-embeds" -o "$(realpath "$THIS_DIR/../../test_vars.go")" \ + -p tpm_enacttrust "$THIS_DIR"/corim-*.cbor diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-class.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-class.cbor new file mode 100644 index 0000000000000000000000000000000000000000..76a849732c3022493bee6f04152a48aa2e5994aa GIT binary patch literal 248 zcmcb~_;oQug{lD*=z?enVQyxT3TDCN%orPQGX9E~yO?nyLjVIBU}{{Xo1|1X literal 0 HcmV?d00001 diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-instance.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-instance.cbor new file mode 100644 index 0000000000000000000000000000000000000000..962db7125c6448476db64028d1dd25f9c3abbac7 GIT binary patch literal 245 zcmcb~_;oQug{lD*=z?enVQyxT3TDCNj2IhlGX9E~wU}`sLjVIBU}{{oGHrXAbbzPO~fc>6(W^eRGIT{x-E@WzKVvJB|cj`Z?)L?7K7FT`F=7ar{ pQqDBPrw^+4R`K6UIC5U~ICF(6c1!ikQi~EZi}UmJ4fPE43;^JhQ4jzC literal 0 HcmV?d00001 diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-digests.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-digests.cbor new file mode 100644 index 0000000000000000000000000000000000000000..6ca816494bde6b78bc0f1e73221c0a4e9c5405cb GIT binary patch literal 262 zcmcb~_;oQug{lD*=z?enVQyxT3TDCNEEpSaGX9EKy_j(!LjVIBU}{{XO51bkXO51bkOZQ~U~9-0SAEXrgZ-0I&NRcP532W8@!v~0a$fZ~Tp?3( z)6C9of2aBv?OLyY%=^%z53-rMzRxw=UN!XR&1|%1u29A96#cT)qQuPN{5*X_Jp(-h E0E_Bfg8%>k literal 0 HcmV?d00001 diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-digest.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-digest.cbor new file mode 100644 index 0000000000000000000000000000000000000000..7da09b5fb6f3d9d5e39be1ab7b84cec781fcc0bf GIT binary patch literal 214 zcmcb~_;oQug{lD*=z?enVQyxT3TDCNOc)z)GX9FFUd*_VA%Fo5Ff}e_$a2j~OfCs2 zDlINyyrEE*QBqP+Y^ATC3KA^=iRvZi=Q1@jFfy?$WN2(!$aq6F;BH#t2Tlza#%b9R z^OpM=6*VqoT*T(az!1j}%*Y;~!03^{z@WegwJd|VLKVBI`ems_iJ8UudHRNW26_en D{tY{g literal 0 HcmV?d00001 diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-instance.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-instance.cbor new file mode 100644 index 0000000000000000000000000000000000000000..07cc90470204bca0388627c091fadc737980fc8b GIT binary patch literal 264 zcmcb~_;oQug{lD*=z?enVQyxT3TDCNOc@(*GX9EKyO?nyLjVIBU}{{yO{Rzlg~a6CRNc(n zf}GUc)Vz|!lFa-(-OLoY-G+=Qj?TWWOj$wsi77#)d3mWtjSCqUGBq|aMkus9^&eGg zur*|ht3GG*!Tw1pXPV*D2i1G4`0phgIj?%0xk44YJM_y^ixM-7^Yio#^$he30IL90 AlklGX9EaU(C3WA%FoDFfuhRX2^2QOH3{a zDJm^4VZ5PGmQhktP;8~Ip9&H!0g37*=jSptGcYo-EM#bGTF7`qHK6u;q2DSNH;X;{ zoxNqRD|~ER$heTHv57H4q1~zfs8WNiAzNJaIhzmmPf9t{44*!z-dn|gFX6~})#E_7 zL^29va|{!yj$y{-n43&m6&rLxz{%C!(@!BF)XB%wS;5;i5-iB&>y};aS{~`)ogd{{ zm1W@U7#QgZWxF^ACc6ZtJGy53q$QS^d1a<)XI448rt5nQ0F?Zq3jhEB literal 0 HcmV?d00001 diff --git a/scheme/tpm-enacttrust/test/corim/src/comid-bad-class.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-class.json new file mode 100644 index 00000000..3d9f2185 --- /dev/null +++ b/scheme/tpm-enacttrust/test/corim/src/comid-bad-class.json @@ -0,0 +1,43 @@ +{ + "tag-identity": { + "id": "00000000-0000-0000-0000-000000000000" + }, + "entities": [ + { + "name": "EnactTrust", + "regid": "https://enacttrust.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "uuid", + "value": "7df7714e-aa04-4638-bcbf-434b1dd720f1" + } + }, + "instance": { + "type": "uuid", + "value": "7df7714e-aa04-4638-bcbf-434b1dd720f1" + } + }, + "measurements": [ + { + "value": { + "digests": [ + "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" + ] + } + } + ] + } + ] + } +} diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustBadInst.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-instance.json similarity index 100% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustBadInst.json rename to scheme/tpm-enacttrust/test/corim/src/comid-bad-instance.json diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustMultDigest.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-multiple-digests.json similarity index 100% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustMultDigest.json rename to scheme/tpm-enacttrust/test/corim/src/comid-bad-multiple-digests.json diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKMult.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-multiple-keys.json similarity index 100% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKMult.json rename to scheme/tpm-enacttrust/test/corim/src/comid-bad-multiple-keys.json diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustGoldenTwo.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-multiple-measurements.json similarity index 100% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustGoldenTwo.json rename to scheme/tpm-enacttrust/test/corim/src/comid-bad-multiple-measurements.json diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustNoDigest.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-no-digest.json similarity index 100% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustNoDigest.json rename to scheme/tpm-enacttrust/test/corim/src/comid-bad-no-digest.json diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustNoInst.json b/scheme/tpm-enacttrust/test/corim/src/comid-bad-no-instance.json similarity index 100% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustNoInst.json rename to scheme/tpm-enacttrust/test/corim/src/comid-bad-no-instance.json diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustGoldenOne.json b/scheme/tpm-enacttrust/test/corim/src/comid-enacttrust-refval.json similarity index 75% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustGoldenOne.json rename to scheme/tpm-enacttrust/test/corim/src/comid-enacttrust-refval.json index c1e39f83..bf723f70 100644 --- a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustGoldenOne.json +++ b/scheme/tpm-enacttrust/test/corim/src/comid-enacttrust-refval.json @@ -1,6 +1,6 @@ { "tag-identity": { - "id": "00000000-0000-0000-0000-000000000000" + "id": "00000000-0000-0000-0000-000000000001" }, "entities": [ { @@ -19,14 +19,14 @@ "environment": { "instance": { "type": "uuid", - "value": "DD6661F0-0928-4401-966B-589EA74E3272" + "value": "7df7714e-aa04-4638-bcbf-434b1dd720f1" } }, "measurements": [ { "value": { "digests": [ - "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" + "sha-256;h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=" ] } } diff --git a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKOne.json b/scheme/tpm-enacttrust/test/corim/src/comid-enacttrust-ta.json similarity index 70% rename from scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKOne.json rename to scheme/tpm-enacttrust/test/corim/src/comid-enacttrust-ta.json index a45f26a5..c75f8588 100644 --- a/scheme/tpm-enacttrust/test/corim/src/ComidTpmEnactTrustAKOne.json +++ b/scheme/tpm-enacttrust/test/corim/src/comid-enacttrust-ta.json @@ -1,6 +1,6 @@ { "tag-identity": { - "id": "00000000-0000-0000-0000-000000000000" + "id": "00000000-0000-0000-0000-000000000002" }, "entities": [ { @@ -19,13 +19,13 @@ "environment": { "instance": { "type": "uuid", - "value": "DD6661F0-0928-4401-966B-589EA74E3272" + "value": "7df7714e-aa04-4638-bcbf-434b1dd720f1" } }, "verification-keys": [ { "type": "pkix-base64-key", - "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6Vwqe7hy3O8Ypa+BUETLUjBNU3rEXVUyt9XHR7HJWLG7XTKQd9i1kVRXeBPDLFnfYru1/euxRnJM7H9UoFDLdA==\n-----END PUBLIC KEY-----" + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkLfat6Jif+izCEg/KBxcN6kF5seJqX1nEiDHtChzV3vJHIgqw4CrTunRP+liAiD3Rg9rLmmVbyUjPKXlwBdHxA==\n-----END PUBLIC KEY-----" } ] } diff --git a/scheme/tpm-enacttrust/test/corim/src/corimMini.json b/scheme/tpm-enacttrust/test/corim/src/corim-enacttrust.json similarity index 50% rename from scheme/tpm-enacttrust/test/corim/src/corimMini.json rename to scheme/tpm-enacttrust/test/corim/src/corim-enacttrust.json index f8b15f3a..2516d008 100644 --- a/scheme/tpm-enacttrust/test/corim/src/corimMini.json +++ b/scheme/tpm-enacttrust/test/corim/src/corim-enacttrust.json @@ -1,4 +1,4 @@ { - "corim-id": "11111111-1111-1111-1111-111111111111", + "corim-id": "00000000-0000-0000-768e-0000000000000", "profile": "https://enacttrust.com/veraison/1.0.0" } diff --git a/scheme/tpm-enacttrust/test/corim/src/corims.yaml b/scheme/tpm-enacttrust/test/corim/src/corims.yaml new file mode 100644 index 00000000..95596606 --- /dev/null +++ b/scheme/tpm-enacttrust/test/corim/src/corims.yaml @@ -0,0 +1,21 @@ +corim: corim-enacttrust +outdir: .. +workdir: ../__build +comids: + enacttrust-valid: + - comid-enacttrust-refval + - comid-enacttrust-ta + enacttrust-bad-instance: + - comid-bad-instance + enacttrust-bad-multiple-keys: + - comid-bad-multiple-keys + enacttrust-bad-no-digest: + - comid-bad-no-digest + enacttrust-bad-no-instance: + - comid-bad-no-instance + enacttrust-bad-class: + - comid-bad-class + enacttrust-bad-multiple-measurements: + - comid-bad-multiple-measurements + enacttrust-bad-multiple-digests: + - comid-bad-multiple-digests diff --git a/scheme/tpm-enacttrust/test/corim/submit-enacttrust-endorsements.sh b/scheme/tpm-enacttrust/test/corim/submit-enacttrust-endorsements.sh new file mode 100755 index 00000000..662b4cf4 --- /dev/null +++ b/scheme/tpm-enacttrust/test/corim/submit-enacttrust-endorsements.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +cocli corim submit -i --corim-file corim-enacttrust-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="https://enacttrust.com/veraison/1.0.0"' --auth=none + diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKBadInst.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKBadInst.cbor deleted file mode 100644 index f7f93964ff9b36caad52ca8e55cbdeb51ecef00c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 364 zcmcb~_;oQufFK%RY`n?%E0R%dG2=pp00uO`)VP=-%QY`Cxg?~hw77)vhC*3JNl8Jm zmA-x|NVEhbs+XLf%hb%k$i%Xcxv^;><4q>D2t~$ouh&&~sxMZm3uZna$1h)PvO7fU zx+>QJ`#tx}-sp>RG~Q&=s@R|l0#2^(o_-1ep-w)Y&I;bHkzheCU$^XX*YZdY@BApw zsw@L%$G}KWDBHy`Fxe$A-O<%7th_MQJfqUs-y*UgQQIlhHN+=0%gHa)xX3jkEVQ!3 zGQuOs+`}u}$K5<4#5*v>GSe_SEGQz?DZs_YEiWyysMJtDwX`BA&&$``!!k7A&BZ6h k(bkp=>;zXo7j#!KSEynS0R6JmqQuPN{5*X_Jp(-h0GFz5{Qv*} diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor deleted file mode 100644 index 3f5de9a20359d761658489221fca02859d558e9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345 zcmcb~_;oQufFK%RY`n?%E0R%oG2=pp00uO`)VP=-%QY`Cxg?~hw77)vhC*3JNl8Jm zmA-x|NVEhbs+XLf%hb%k$i%Xcxv^;>;|T@<9?4Oi!rWrncP`$T`|6an8^Qy<0D^#)DpkJ0+l$cqZpQmrA IXP{>Q0O#UEfdBvi diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor deleted file mode 100644 index d0c27f53329472e29dfe607daf1df8e9d2f547d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 245 zcmcb~_;oQufFK%RY`n?%D`LZ9#)S+43}}F#_!(-J>$YPc{?%Z`}0+|Q^8D7uiTv57H4 zq1~zfs8WNiAzNJaIhzmmPf9t{44*!z-dn|gFX6~})#Gr5Ovz0%JGcFv>R+^Lz5X%p qLytblX6pJr*KB*$(4RN6(Vn?N6}waP%TkLHGmG={^bPe4^b7zeo>vh7 diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor deleted file mode 100644 index d18bf630ce45259be89d3f98fb94af6865d86acc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmcb~_;oQufFK%RY`n?%D`NFx#)S+43}}F#_!(-J>$YPc{?%Z`}0+|Q_}aUtVErluyw z2!(d1{-a6_wuWqR)#q$J*gq-dOf!7?pn7i=|Gk7G=T(nms;LL6NkUP>T%n5H75ZhV QMTwck`FZ+=dIow10767mUH||9 diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor deleted file mode 100644 index fd7dafdbadd5c2d3773e848fb98ac35e507d16da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192 zcmcb~_;oQufFK%RY`n?%E24Ta<3ff21~kCbxR@c!H7_x_B&4XcxPF?M*;(b0wdJ24CV?|?566Mr4}V-7U$>b8|oS882|wBYc(DK diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor deleted file mode 100644 index 131c3cb96bd062d154d6bc95bffa2bb1b90225f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 242 zcmcb~_;oQufFK%RY`n?%D`M?p#)S+43}}FqP;(b?CPDJv*HF(s%pFE6#IaUtVErp6}52!(d1{-a6_wuWqR)#q$J*gq-d oOf!7?pn7i=|Gk7G=T(n0SEyolhkjXVQDSCsexAOeo`IeL09(XPbpQYW diff --git a/scheme/tpm-enacttrust/test/tokens/Makefile b/scheme/tpm-enacttrust/test/evidence/Makefile similarity index 100% rename from scheme/tpm-enacttrust/test/tokens/Makefile rename to scheme/tpm-enacttrust/test/evidence/Makefile diff --git a/scheme/tpm-enacttrust/test/tokens/basic.json b/scheme/tpm-enacttrust/test/evidence/basic.json similarity index 100% rename from scheme/tpm-enacttrust/test/tokens/basic.json rename to scheme/tpm-enacttrust/test/evidence/basic.json diff --git a/scheme/tpm-enacttrust/test/tokens/basic.token b/scheme/tpm-enacttrust/test/evidence/basic.token similarity index 100% rename from scheme/tpm-enacttrust/test/tokens/basic.token rename to scheme/tpm-enacttrust/test/evidence/basic.token diff --git a/scheme/tpm-enacttrust/test/evidence/submit-enacattrust-evidence.sh b/scheme/tpm-enacttrust/test/evidence/submit-enacattrust-evidence.sh new file mode 100755 index 00000000..cbb68399 --- /dev/null +++ b/scheme/tpm-enacttrust/test/evidence/submit-enacattrust-evidence.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +set -euo pipefail + +session_path=$(curl -k -X POST -D - https://localhost:8443/challenge-response/v1/newSession 2>/dev/null | grep "location:" | cut -f2 -d" " | tr -d '\r') +echo "session: $session_path" + +set +e +echo "----> post" +curl -k -X POST -D - -H "content-type: application/vnd.enacttrust.tpm-evidence" --data-binary @basic.token https://localhost:8443/challenge-response/v1/"$session_path" +echo "" +echo "" +set -e + +echo "----> delete $session_path" +curl -k -X DELETE -D - https://localhost:8443/challenge-response/v1/"$session_path" +echo "done." diff --git a/scheme/tpm-enacttrust/test/refval.json b/scheme/tpm-enacttrust/test/refval.json deleted file mode 100644 index 6995e975..00000000 --- a/scheme/tpm-enacttrust/test/refval.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "scheme": "TPM_ENACTTRUST", - "type": "REFERENCE_VALUE", - "subType": "enacttrust-tpm.sw-component", - "attributes": { - "enacttrust-tpm.alg-id": 1, - "enacttrust-tpm.digest": "h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", - "enacttrust-tpm.node-id": "7df7714e-aa04-4638-bcbf-434b1dd720f1" - } -} diff --git a/scheme/tpm-enacttrust/test/trustanchor.json b/scheme/tpm-enacttrust/test/trustanchor.json deleted file mode 100644 index 749c0f9f..00000000 --- a/scheme/tpm-enacttrust/test/trustanchor.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "scheme": "TPM_ENACTTRUST", - "type": "VERIFICATION_KEY", - "attributes": { - "enacttrust-tpm.node-id": "7df7714e-aa04-4638-bcbf-434b1dd720f1", - "enacttrust.ak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkLfat6Jif+izCEg/KBxcN6kF5seJqX1nEiDHtChzV3vJHIgqw4CrTunRP+liAiD3Rg9rLmmVbyUjPKXlwBdHxA==\n-----END PUBLIC KEY-----" - } -} diff --git a/scheme/tpm-enacttrust/test_vars.go b/scheme/tpm-enacttrust/test_vars.go new file mode 100644 index 00000000..91c00dee --- /dev/null +++ b/scheme/tpm-enacttrust/test_vars.go @@ -0,0 +1,33 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package tpm_enacttrust + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( + //go:embed test/corim/corim-enacttrust-bad-class.cbor + corimEnacttrustBadClass []byte + + //go:embed test/corim/corim-enacttrust-bad-instance.cbor + corimEnacttrustBadInstance []byte + + //go:embed test/corim/corim-enacttrust-bad-multiple-digests.cbor + corimEnacttrustBadMultipleDigests []byte + + //go:embed test/corim/corim-enacttrust-bad-multiple-keys.cbor + corimEnacttrustBadMultipleKeys []byte + + //go:embed test/corim/corim-enacttrust-bad-multiple-measurements.cbor + corimEnacttrustBadMultipleMeasurements []byte + + //go:embed test/corim/corim-enacttrust-bad-no-digest.cbor + corimEnacttrustBadNoDigest []byte + + //go:embed test/corim/corim-enacttrust-bad-no-instance.cbor + corimEnacttrustBadNoInstance []byte + + //go:embed test/corim/corim-enacttrust-valid.cbor + corimEnacttrustValid []byte +) diff --git a/scheme/tpm-enacttrust/test_vectors.go b/scheme/tpm-enacttrust/test_vectors.go deleted file mode 100644 index ac4704d8..00000000 --- a/scheme/tpm-enacttrust/test_vectors.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package tpm_enacttrust - -import _ "embed" - -var ( - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor - unsignedCorimComidTpmEnactTrustAKOne []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenOne.cbor - unsignedCorimComidTpmEnactTrustGoldenOne []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustAKMult.cbor - unsignedCorimComidTpmEnactTrustAKMult []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustBadInst.cbor - unsignedCorimComidTpmEnactTrustBadInst []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor - unsignedCorimComidTpmEnactTrustNoInst []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor - unsignedCorimComidTpmEnactTrustMultDigest []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor - unsignedCorimComidTpmEnactTrustGoldenTwo []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor - unsignedCorimComidTpmEnactTrustNoDigest []byte - - //go:embed test/corim/unsignedCorimMiniComidTpmEnactTrustAKBadInst.cbor - unsignedCorimComidTpmEnactTrustAKBadInst []byte -) diff --git a/scripts/generate-corims b/scripts/generate-corims new file mode 100755 index 00000000..396c3d9d --- /dev/null +++ b/scripts/generate-corims @@ -0,0 +1,403 @@ +#!/usr/bin/env python3 +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +import argparse +import json +import logging +import os +import shlex +import shutil +import subprocess +import sys +from datetime import datetime +from pathlib import Path +import textwrap +from typing import Optional, Union + + +log_colors = { + 'DEBUG': '\033[0;37m', # Gray ] ("closing" bracket to satisfy Vim indent calc.) + 'INFO': '\033[0;32m', # Green ] + 'WARNING': '\033[0;33m', # Yellow ] + 'ERROR': '\033[0;31m', # Red ] + 'CRITICAL': '\033[1;31m', # Bold Red ] +} +reset = '\033[0m' # ] + +class LogFormatter(logging.Formatter): + def format(self, record): + color = log_colors.get(record.levelname, reset) + record.levelname = f'{color}{record.levelname:>8s}{reset}' + return super().format(record) + +handler = logging.StreamHandler() +handler.setFormatter(LogFormatter('%(levelname)-8s: %(message)s')) +logger = logging.getLogger() +logger.setLevel(logging.INFO) +logger.addHandler(handler) + + +try: + import yaml +except ImportError: + logging.error('please install pyyaml (e.g. "pip install pyyaml")') + sys.exit(1) + +if not shutil.which('cocli'): + logging.error( + 'please install cocli and ensure it is in PATH: ' + 'go install github.com/veraison/cocli@latest && export PATH=$PATH:${GOPATH:-$HOME/go}/bin' + ) + sys.exit(1) + + +class CoMIDSet: + + def __init__( + self, + name: str, + paths: list[str], + sign: Optional[bool] = None, + key: Optional[str] = None, + ): + self.name = name + self.paths = paths + self.should_sign = sign + self.key = key + + +class BuildSpec: + ''' + A build spec that describes how one or more CoRIMs based on the same CoRIM + template (effectively, the same profile) can be built from one or more + CoMID sets. + ''' + + @staticmethod + def load(path: str) -> BuildSpec: + '''Load the spec from the specified file.''' + root = os.path.dirname(path) + + with open(path) as fh: + fields = yaml.safe_load(fh) + + comid_specs = fields.pop('comids') + if not comid_specs: + raise ValueError(f'no CoMIDs in spec') + + comids = [CoMIDSet(k, **(v if hasattr(v, 'items') else {'paths': v})) for k, v in comid_specs.items()] + return BuildSpec(root, comid_sets=comids, **fields) + + def __init__( + self, + root: str, + corim: str, + comid_sets: list[CoMIDSet], + outdir: str, + workdir: str = '/tmp/create-corim-workdir', + sign: bool = False, + key: Optional[str] = None, + meta: Optional[str] = None, + ): + self.root = resolve(root) + self.corim_path = corim + self.comid_sets = comid_sets + self.outdir = resolve(root, outdir) + self.workdir = resolve(root, workdir) + self.should_sign = sign + self.key = key + self.meta = meta + + def build(self): + ''' + Build the spec, generating a CoRIM for every CoMID set. + ''' + if os.path.exists(self.workdir): + logging.debug('removing existing working directory...') + shutil.rmtree(self.workdir) + logging.debug(f'creating working directory {self.workdir}...') + os.mkdir(self.workdir) + + for i, comid_set in enumerate(self.comid_sets, 1): + logging.info(f'building {comid_set.name}...') + corim_template_path = self.instantiate_corim_template(i) + comid_paths = self.build_comids(comid_set) + + should_sign = self.should_sign if comid_set.should_sign is None else comid_set.should_sign + key_path = self.key if comid_set.key is None else comid_set.key + + if should_sign and key_path is None: + raise ValueError(f'comid set {comid_set.name} must be signed by no key specified') + else: + key_path = None + + self.build_corim(comid_set.name, corim_template_path, comid_paths, key_path) + + def instantiate_corim_template(self, index: int): + ''' + creates a CoRIM JSON "template" for cocli in the working directory by + using template in the build spec's corim_path, and replacing the last + six bytes (the last dash-separated segment in string representation) + of the corim-id UUID with the specified index. + ''' + corim_path = self.corim_path + if not corim_path.endswith('.json'): + corim_path += '.json' + + corim_path = resolve(self.root, corim_path) + name_root = os.path.splitext(os.path.basename(corim_path))[0] + outpath = resolve(self.workdir, f'{name_root}-{index:02d}.json') + + logging.debug(f'creating corim template {outpath} from {corim_path}...') + + with open(corim_path) as fh: + corim_spec = json.load(fh) + + uuid = corim_spec.get('corim-id', '00000000-0000-0000-0000-0000000000000') + corim_spec['corim-id'] = uuid.rsplit('-', 1)[0] + f'-00000000000{index:02d}' + + with open(outpath, 'w') as wfh: + json.dump(corim_spec, wfh) + + return outpath + + def build_comids(self, comid_set: CoMIDSet) -> list[Path]: + '''Compile indidual CoMIDs into CBOR.''' + ret = [] + for comid_template_path in comid_set.paths: + if not comid_template_path.endswith('.json'): + comid_template_path += '.json' + + name_root = os.path.splitext(os.path.basename(comid_template_path))[0] + if not name_root.startswith('comid-'): + name_root = f'comid-{name_root}' + + comid_template_path = resolve(self.root, comid_template_path) + outpath = resolve(self.workdir, f'{name_root}.cbor') + logging.debug(f'compiling {outpath}...') + self.cocli(f'comid create -t "{comid_template_path}" -o "{self.workdir}"') + ret.append(outpath) + + return ret + + def build_corim( + self, + name_root: str, + corim_template_path: Union[Path, str], + comid_paths: list[Path], + signing_key: Optional[Path | str], + ): + '''Compile CoRIM into CBOR.''' + if not name_root.startswith('corim-'): + name_root = f'corim-{name_root}' + + if not name_root.endswith('.cbor'): + name_root = f'{name_root}.cbor' + + outpath = os.path.join(self.outdir, f'unsigned-{name_root}' if signing_key else name_root) + logging.debug(f'compiling {outpath}...') + + cmd = f'corim create -t "{corim_template_path}" -o "{outpath}"' + for path in comid_paths: + cmd = f'{cmd} -m {path}' + + self.cocli(cmd) + + if signing_key: + self.ensure_meta() + + signed_path = os.path.join(self.outdir, f'signed-{name_root}' if signing_key else name_root) + logging.info(f'signing {outpath}...') + self.cocli(f'corim sign -f "{outpath}" -k "{signing_key}" -m "{self.meta}" -o "{signed_path}"') + + def cocli(self, command): + '''Run the specified cocli (sub-)command.''' + logging.debug(f' cocli {command}') + args = ['cocli'] + shlex.split(command) + result = subprocess.run( + args, + cwd=self.root, + text=True, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + ) + if result.returncode == 0: + for line in result.stdout.split('\n'): + logging.debug(f' {line}') + else: + logging.error(f'cocli {command}') + for line in result.stdout.split('\n'): + logging.error(f' {line}') + raise RuntimeError('cocli failed') + + def ensure_meta(self): + '''Ensure a meta file exists, creating one if it doesn't.''' + if not self.meta: + meta_path = resolve(self.workdir, 'meta.json') + now = datetime.now() + with open(meta_path, 'w') as wfh: + json.dump({ + 'signer': {'name': 'veraison-services-test-case-generator'}, + 'validity': { + 'not-before': now.isoformat(), + 'not-after': now.replace(year=now.year+100).isoformat(), + }, + }, wfh) + self.meta = meta_path + + +def resolve(*parts: Union[Path, str]) -> Path: + '''wrapper around Path.resolve()''' + if not parts: + raise ValueError('must specify at least one path segment') + return Path(*parts).resolve(strict=False) + + +def discover_specs(path: str) -> list[str]: + ''' + Discover and return a list of YAML "spec" files that contain instructions + on how CoRIMs ought to be built. + + If the path specified points to a file, that file is assumed to be the + spec. If the path is a directory, that directory is recursively traversed, + locating all files ending with "corims.yaml". + ''' + if os.path.isfile(path): + return [path] + + if not os.path.isdir(path): + logging.error(f'not a valid path: {path}') + sys.exit(1) + + logging.info("discovering corim.yaml's...") + ret = [] + for root, _, files in os.walk(path): + for file in files: + if file.endswith('corims.yaml'): + ret.append(os.path.join(root, file)) + + return ret + + +help=''' +Generate CoRIMs based on a YAML specification. +''' + +epilog=''' +SPECIFICATION + +A specification is A YAML document with the following top-level entries: + + corim: path, relative to the spec, of the CoRIM JSON template (.json + extension can optionally be omitted). If the template contains the + "corim-id" entry, the segment (last six bytes) of this UUID will be + automatically, ovewritten with an auto-incrementing index for each + CoMID set (see below), starting at 1. + + outdir: path, relative to the spec, of the output directory into which the + created CoRIM(s) will be written + +workdir: (optional) working directory (will be created) where intemediate + artifacts (compiled CoMIDs, populated CoRIM template, etc) will be + located. WARNING: if this directory exists, its prior contents will + be DELETED. If not specified, /tmp/create-corim-workdir will be used. + + sign: (optional) boolean flag indicating whether a signed version of the + CoRIM will also be created. May be overridden on per-CoMID set level + (see below). If true, then the name of the unsigned CoRIM will be + prefixed with "unsigned-" and the signed CoRIM with "signed-". If this + is true then a key (see below) MUST also be specified. If not + specified, false is assumed. + + key: (required when sign is true) path, relative to the spec, of the key + file that will be used to sign CoRIMs, if sign (see above) is true. If + sign is false, this will be ignored. May be overridden on per-CoMID + set level (see bellow). The key must be in a format understood by + cocli. + + meta: (optonal) path, relative to the spec, of the JSON description that will + be used to generate the Meta entry when signing the CoRIM. If sign (see + above) is false, this will be ignored. If sign is true, and meta, is not + specified, an entry will instead be generated by the script. + + comids: a mapping of names to CoMID sets (see next section). The name will be + used as the root of the name of the generated CoRIM. The CoRIM will + use the template specified by corim (see above) for top-level entries, + and will contain CoMIDs specified by the set. + +COMID SETS + +A CoMID set is either a map or a list describing the CoMIDs that will be used +to create a CoRIM. If it is a map, it may contain the following entries: + + paths: a list of paths, relative to the spec, of the CoMID JSON templates + (.json extension can optionally be omitted). This is the only required + parameter. + + sign: (optional) overrides the global sign value (see above) for this set + + key: (optional) overrides the global key value (see above) for this set + +If a CoMID set is a list, it will be treated as a map with just the paths entry. + +EXAMPLE + + corim: corim-cca + outdir: .. + workdir: ../__build + sign: true + key: ../ec384.jwk + comids: + cca-platform: + - comid-cca-platform-refval + - comid-cca-platform-ta + cca-realm: + sign: false + paths: + - comid-cca-realm-refval + +''' + +def main(): + parser = argparse.ArgumentParser( + description=help, + epilog=epilog, + formatter_class=argparse.RawTextHelpFormatter, + ) + parser.add_argument( + 'path', + help=textwrap.dedent(''' + path to the spec or a directry; if a directory, it will be scanned recusively + finding and processing all files ending with "corims.yaml" + ''').strip(), + ) + parser.add_argument('-v', '--verbose', action='store_true', help='enable debug output') + args = parser.parse_args() + + if args.verbose: + logging.getLogger().setLevel(logging.DEBUG) + + spec_files = discover_specs(args.path) + if not spec_files: + logging.error("no corim.yaml's found") + sys.exit(1) + + for spec_path in spec_files: + logging.info(f'processing {spec_path}...') + try: + spec = BuildSpec.load(spec_path) + except Exception as e: + logging.critical(f'could not load spec: {e}') + sys.exit(1) + + try: + spec.build() + except Exception as e: + logging.critical(f'could not build spec: {e}') + sys.exit(1) + + logging.info('done.') + + +if __name__ == '__main__': + main() diff --git a/scripts/generate-test-vector-embeds b/scripts/generate-test-vector-embeds new file mode 100755 index 00000000..04fa3117 --- /dev/null +++ b/scripts/generate-test-vector-embeds @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +import argparse +import logging +import os +import sys +import string +from datetime import datetime +import textwrap +from typing import TextIO + + +log_colors = { + 'DEBUG': '\033[0;37m', # Gray ] ("closing" bracket to satisfy Vim indent calc.) + 'INFO': '\033[0;32m', # Green ] + 'WARNING': '\033[0;33m', # Yellow ] + 'ERROR': '\033[0;31m', # Red ] + 'CRITICAL': '\033[1;31m', # Bold Red ] +} +reset = '\033[0m' # ] + +class LogFormatter(logging.Formatter): + def format(self, record): + color = log_colors.get(record.levelname, reset) + record.levelname = f'{color}{record.levelname:>8s}{reset}' + return super().format(record) + +handler = logging.StreamHandler() +handler.setFormatter(LogFormatter('%(levelname)-8s: %(message)s')) +logger = logging.getLogger() +logger.setLevel(logging.INFO) +logger.addHandler(handler) + + +preamble=''' +// Copyright {year} Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package {package} + +// NOTE: this file is generated. DO NOT EDIT + +import _ "embed" + +var ( +''' + +postamble=''' +) +''' + + +def write_preamble(wfh: TextIO, package: str): + wfh.write(preamble.format( + year=datetime.now().year, + package=package, + ).lstrip()) + + +def write_postamble(wfh: TextIO): + wfh.write(postamble.lstrip()) + + +to_replace = string.punctuation + string.whitespace +trans_table = str.maketrans(to_replace, '-' * len(to_replace)) + + +def generate_variable_name(path: str, use_ext: bool, use_path: bool) -> str: + if not path: + raise ValueError('empty path') + + parts = path.split(os.sep) if use_path else [path.split(os.sep)[-1]] + + if use_ext: + root, ext = os.path.splitext(parts[-1]) + parts = parts[:-1] + [root, ext[1:]] + else: + parts[-1] = os.path.splitext(parts[-1])[0] + + parts = [p.lower() for part in parts for p in part.translate(trans_table).split('-') if p] + parts = [parts[0]] + [p.capitalize() for p in parts[1:]] + + return ''.join(parts) + + +help=''' +Generate a Go file embedding specified inputs as []byte variables. +''' + + +def main(): + parser = argparse.ArgumentParser( + description=help, + formatter_class=argparse.RawTextHelpFormatter, + ) + parser.add_argument( + 'paths', + nargs='+', + metavar='PATH', + help='path(s) to files to be embeded', + ) + parser.add_argument( + '-o', '--output', + help='path to output file (default: STDOUT)', + ) + parser.add_argument( + '-p', '--package', + default='test', + help='Go package name used in the output', + ) + parser.add_argument( + '-E', '--extensions-in-names', + action='store_true', + help=textwrap.dedent(''' + if true, input file extensions will be used in forming the variable + name; the default behavoir is to omit the extension. This is needed + if the test vectors feature files that only differ in their extension. + ''').strip(), + ) + parser.add_argument( + '-P', '--paths-in-names', + action='store_true', + help=textwrap.dedent(''' + if true, the entire path of specified input files will be used in + forming the variable name; the default behavoir is to only use the + basename. This is needed if the test vectors feature files with + the same names that reside in different directories. + ''').strip(), + ) + parser.add_argument( + '-v', '--verbose', + action='store_true', + help='enable debug output', + ) + args = parser.parse_args() + + if args.verbose: + logging.getLogger().setLevel(logging.DEBUG) + + outpath = os.getcwd() + wfh = sys.stdout + if args.output: + logger.info(f'generating {args.output}...') + outpath = os.path.dirname(args.output) + wfh = open(args.output, 'w') + else: + logger.info('generating STDOUT...') + + try: + write_preamble(wfh, args.package) + + for i, path in enumerate(args.paths): + logger.info(f'processing {path}...') + if not os.path.isfile(path): + raise ValueError(f'not a file: {path}') + + relpath = os.path.relpath(path, outpath) + logger.debug(f' relpath: {relpath}') + + var_name = generate_variable_name( + relpath, + args.extensions_in_names, + args.paths_in_names, + ) + logger.debug(f' var_name: {var_name}') + + if i: + wfh.write('\n') + + wfh.write(f'\t//go:embed {relpath}\n') + wfh.write(f'\t{var_name} []byte\n') + + write_postamble(wfh) + logger.info('done.') + + except Exception as e: + logger.critical(e) + sys.exit(1) + finally: + if args.output: + logger.debug(f'closing {args.output}') + wfh.close() + + +if __name__ == '__main__': + main() diff --git a/scripts/get-veraison-version b/scripts/get-veraison-version index fbb50db5..efaf1b15 100755 --- a/scripts/get-veraison-version +++ b/scripts/get-veraison-version @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 # VERAISON_BUILD_VERSION, if set, overrides version from Git if [[ "$VERAISON_BUILD_VERSION" != "" ]]; then diff --git a/tools.go b/tools.go index bd18e3e7..a3dcca26 100644 --- a/tools.go +++ b/tools.go @@ -1,3 +1,5 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 //go:build tools // +build tools diff --git a/verification/cmd/verification-service/main.go b/verification/cmd/verification-service/main.go index 846e6ab0..6444d941 100644 --- a/verification/cmd/verification-service/main.go +++ b/verification/cmd/verification-service/main.go @@ -1,4 +1,4 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -44,11 +44,11 @@ func main() { } cfg := cfg{ ListenAddr: DefaultListenAddr, - Protocol: "https", + Protocol: "https", } subs, err := config.GetSubs(v, "*vts", "*verifier", "*verification", "*logging", - "*sessionmanager") + "*sessionmanager") if err != nil { log.Fatalf("Could not read config: %v", err) } diff --git a/verification/sessionmanager/common_test.go b/verification/sessionmanager/common_test.go index 5edacd52..ad32dd22 100644 --- a/verification/sessionmanager/common_test.go +++ b/verification/sessionmanager/common_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package sessionmanager @@ -16,4 +16,3 @@ var ( testTTL, _ = time.ParseDuration("1m30s") testShortTTL, _ = time.ParseDuration("1s") ) - diff --git a/verification/sessionmanager/memcached.go b/verification/sessionmanager/memcached.go index 21ff89b7..4f576e9b 100644 --- a/verification/sessionmanager/memcached.go +++ b/verification/sessionmanager/memcached.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package sessionmanager @@ -55,8 +55,8 @@ func (o *Memcached) SetSession( ttl time.Duration, ) error { item := &memcache.Item{ - Key: makeKey(id, tenant), - Value: session, + Key: makeKey(id, tenant), + Value: session, Expiration: int32(ttl.Seconds()), } return o.client.Set(item) diff --git a/verification/sessionmanager/memcached_fakeserver_test.go b/verification/sessionmanager/memcached_fakeserver_test.go index 6d130b62..18726fb4 100644 --- a/verification/sessionmanager/memcached_fakeserver_test.go +++ b/verification/sessionmanager/memcached_fakeserver_test.go @@ -15,8 +15,9 @@ limitations under the License. */ // note: this has been taken nearly verbatim from https://github.com/bradfitz/gomemcache -// the only change being the package directive, and some comment change -// to pacify lint +// +// the only change being the package directive, and some comment change +// to pacify lint package sessionmanager import ( @@ -35,8 +36,9 @@ import ( ) var ( - crlf = []byte("\r\n") + crlf = []byte("\r\n") ) + type testServer struct { mu sync.Mutex m map[string]serverItem @@ -126,7 +128,7 @@ func (c *testConn) handleRequestLine(line string) bool { } fmt.Fprintf(c.bw, "VALUE %s %d %d %d\r\n", key, item.flags, len(item.data), item.casUniq) c.bw.Write(item.data) // nolint: errcheck - c.bw.Write(crlf) // nolint: errcheck + c.bw.Write(crlf) // nolint: errcheck } return c.reply("END") } diff --git a/verification/sessionmanager/memcached_test.go b/verification/sessionmanager/memcached_test.go index e6f1e1cd..b8ea498c 100644 --- a/verification/sessionmanager/memcached_test.go +++ b/verification/sessionmanager/memcached_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package sessionmanager @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" ) - func Test_Memcached_SetGetDelOK(t *testing.T) { sm := NewMemcached() diff --git a/verification/sessionmanager/new.go b/verification/sessionmanager/new.go index 45186ce8..5b3a76ad 100644 --- a/verification/sessionmanager/new.go +++ b/verification/sessionmanager/new.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package sessionmanager @@ -11,7 +11,6 @@ import ( "github.com/veraison/services/config" ) - const DefaultBackend = "ttlcache" type cfg struct { @@ -21,7 +20,7 @@ type cfg struct { func (o cfg) Validate() error { supportedBackends := map[string]bool{ - "ttlcache": true, + "ttlcache": true, "memcached": true, } diff --git a/vts/appraisal/appraisal.go b/vts/appraisal/appraisal.go deleted file mode 100644 index 700b1133..00000000 --- a/vts/appraisal/appraisal.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022-2023 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 - -package appraisal - -import ( - "encoding/base64" - "fmt" - "strings" - - "github.com/veraison/ear" - "github.com/veraison/services/config" - "github.com/veraison/services/policy" - "github.com/veraison/services/proto" -) - -// Appraisal provides an appraisal context internally within the VTS (e.g. for -// policy evaluation). It is the analog of proto.AppraisalContext, but with a -// deserialized AttestationResult. -type Appraisal struct { - Scheme string - EvidenceContext *proto.EvidenceContext - Result *ear.AttestationResult - SignedEAR []byte -} - -func New(tenantID string, nonce []byte, scheme string) *Appraisal { - appraisal := Appraisal{ - Scheme: scheme, - EvidenceContext: &proto.EvidenceContext{ - TenantId: tenantID, - }, - Result: ear.NewAttestationResult(scheme, config.Version, config.Developer), - } - - encodedNonce := base64.URLEncoding.EncodeToString(nonce) - appraisal.Result.Nonce = &encodedNonce - - appraisal.Result.VerifierID.Build = &config.Version - appraisal.Result.VerifierID.Developer = &config.Developer - - appraisal.InitPolicyID() - - return &appraisal -} - -func (o Appraisal) GetContext() *proto.AppraisalContext { - return &proto.AppraisalContext{ - Evidence: o.EvidenceContext, - Result: o.SignedEAR, - } -} - -func (o Appraisal) SetAllClaims(claim ear.TrustClaim) { - for _, submod := range o.Result.Submods { - submod.TrustVector.SetAll(claim) - } -} - -func (o Appraisal) AddPolicyClaim(name, claim string) { - for _, submod := range o.Result.Submods { - if submod.AppraisalExtensions.VeraisonPolicyClaims == nil { - claimsMap := make(map[string]interface{}) - submod.AppraisalExtensions.VeraisonPolicyClaims = &claimsMap - } - (*submod.AppraisalExtensions.VeraisonPolicyClaims)[name] = claim - } -} - -func (o *Appraisal) UpdatePolicyID(pol *policy.Policy) error { - if err := pol.Validate(); err != nil { - return err - } - - subID := pol.UUID.String() - - for _, submod := range o.Result.Submods { - updatedID := strings.Join([]string{*submod.AppraisalPolicyID, subID}, "/") - submod.AppraisalPolicyID = &updatedID - } - - return nil -} - -func (o *Appraisal) InitPolicyID() { - for _, submod := range o.Result.Submods { - policyID := fmt.Sprintf("policy:%s", o.Scheme) - submod.AppraisalPolicyID = &policyID - } -} diff --git a/vts/appraisal/context.go b/vts/appraisal/context.go new file mode 100644 index 00000000..d5f8afba --- /dev/null +++ b/vts/appraisal/context.go @@ -0,0 +1,214 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package appraisal + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "reflect" + "strings" + + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/services/config" + "github.com/veraison/services/proto" + "google.golang.org/protobuf/types/known/structpb" +) + +// Context is the appraisal context for an attestation. It maintains the state +// of the attestation through the pipeline, between the calls to the +// scheme-specific functionality. +type Context struct { + Scheme string `json:"scheme"` + TrustAnchorIDs []*comid.Environment `json:"trust-anchor-ids"` + ReferenceValueIDs []*comid.Environment `json:"reference-value-ids"` + Evidence *Evidence `json:"evidence"` + Claims map[string]any `json:"claims"` + Result *ear.AttestationResult `json:"result"` + SignedEAR []byte `json:"signed-ear"` +} + +// NewContext instantiates a new Context using the provided evidence. The +// AttestationResult result inside the context is initialized with a single +// submod called "ERROR" (this is replaced when the attestation scheme is +// known). +func NewContext(evidence *Evidence) *Context { + ac := Context{ + Evidence: evidence, + Claims: make(map[string]any), + // "ERROR" is used for the default submod name as we don't know + // the attestation scheme yet; the submod will be moved under the scheme + // name at the time the scheme is set. + Result: ear.NewAttestationResult("ERROR", config.Version, config.Developer), + } + + encodedNonce := base64.URLEncoding.EncodeToString(evidence.Nonce) + ac.Result.Nonce = &encodedNonce + + return &ac +} + +// SetScheme sets the scheme used in the attestation tracked by this Context. +// This updates the submod in the AttestationResult from "ERROR" to the name of +// the scheme. +func (o *Context) SetScheme(scheme string) error { + var ok bool + if _, ok = o.Result.Submods[scheme]; ok { + return fmt.Errorf("submod %q already exists in result", scheme) + } + + o.Scheme = scheme + // now that the scheme is known, move the default submod (which is + // currently under "ERROR") to under the scheme's name. + o.Result.Submods[scheme], ok = o.Result.Submods["ERROR"] + if !ok { + return errors.New("submod \"ERROR\" not in result; has the scheme already been set?") + } + delete(o.Result.Submods, "ERROR") + + o.InitPolicyID() + + return nil +} + +// StoreLabel returns the label that should be used when querying the CoRIMs +// store for items associated with attestation tracked by this context. +func (o *Context) StoreLabel() string { + return fmt.Sprintf("%s/%s", o.Evidence.TenantID, o.Scheme) +} + +// SetAllClaims sets all claims in all submods in the AttestationResult tracked +// by this Context to the specified value. +func (o *Context) SetAllClaims(claim ear.TrustClaim) { + for _, submod := range o.Result.Submods { + submod.TrustVector.SetAll(claim) + } +} + +// AddPolicyClaim adds the specified claim to all submods in the +// AttestationResult tracked by this Context. (Note: this is primarily intended +// for problem reporting, as there aren't many other claims that it would make +// sense to set for all submods). +func (o *Context) AddPolicyClaim(name, claim string) { + for _, submod := range o.Result.Submods { + if submod.AppraisalExtensions.VeraisonPolicyClaims == nil { + claimsMap := make(map[string]any) + submod.AppraisalExtensions.VeraisonPolicyClaims = &claimsMap + } + (*submod.AppraisalExtensions.VeraisonPolicyClaims)[name] = claim + } +} + +// InitPolicyID initializes the AppraisalPolicyID in the AttestationResult +// tracked by this Context to value based on the attestation scheme. +func (o *Context) InitPolicyID() { + for _, submod := range o.Result.Submods { + policyID := fmt.Sprintf("policy:%s", o.Scheme) + submod.AppraisalPolicyID = &policyID + } +} + +// UpdatePolicyID updates AppraisalPolicyID in all submods with the specified +// element that gets joined with "/" to the existing AppraisalPolicyID value. +func (o *Context) UpdatePolicyID(polID string) error { + for _, submod := range o.Result.Submods { + updatedID := strings.Join([]string{*submod.AppraisalPolicyID, polID}, "/") + submod.AppraisalPolicyID = &updatedID + } + + return nil +} + +// DescribeTrustAnchorIDs returns a string value describing the trust anchor +// IDs tracked by this Context. +func (o *Context) DescribeTrustAnchorIDs() string { + buf, _ := json.Marshal(o.TrustAnchorIDs) + return string(buf) +} + +// ToProtobuf converts this Context to proto.AppraisalContext +func (o *Context) ToProtobuf() (*proto.AppraisalContext, error) { + trustAnchorIDStrings := make([]string, len(o.TrustAnchorIDs)) + for i, taID := range o.TrustAnchorIDs { + taJSON, err := json.Marshal(taID) + if err != nil { + return nil, err + } + + trustAnchorIDStrings[i] = string(taJSON) + } + + referenceValueIDStrings := make([]string, len(o.ReferenceValueIDs)) + for i, rvID := range o.ReferenceValueIDs { + rvJSON, err := json.Marshal(rvID) + if err != nil { + return nil, err + } + + referenceValueIDStrings[i] = string(rvJSON) + } + + pbClaims, err := claimsToStruct(o.Claims) + if err != nil { + return nil, err + } + + return &proto.AppraisalContext{ + Evidence: &proto.EvidenceContext{ + TenantId: o.Evidence.TenantID, + TrustAnchorIds: trustAnchorIDStrings, + ReferenceIds: referenceValueIDStrings, + Evidence: pbClaims, + }, + Result: o.SignedEAR, + }, nil +} + +func claimsToStruct(m map[string]any) (*structpb.Struct, error) { + // annoyingly, structpb can't handle a, e.g., []int64, though + // it can handle []any that contains int64's,so we need to + // do this normalization; + normalized := make(map[string]any) + for k, v := range m { + normalized[k] = normalize(v) + } + + return structpb.NewStruct(normalized) +} + +func normalize(v any) any { + val := reflect.ValueOf(v) + + switch val.Kind() { + case reflect.Slice: + normalizedSlice := reflect.MakeSlice( + reflect.SliceOf(reflect.TypeFor[any]()), + val.Len(), + val.Cap(), + ) + + for i := 0; i < val.Len(); i++ { + normalizedSlice.Index(i).Set(reflect.ValueOf(normalize(val.Index(i).Interface()))) + } + + return normalizedSlice.Interface() + case reflect.Map: + normalizedMap := reflect.MakeMap( + reflect.MapOf( + reflect.TypeFor[string](), + reflect.TypeFor[any](), + ), + ) + + for _, key := range val.MapKeys() { + normalizedMap.SetMapIndex(key, reflect.ValueOf(normalize(val.MapIndex(key).Interface()))) + } + + return normalizedMap.Interface() + default: + return v + } +} diff --git a/vts/appraisal/evidence.go b/vts/appraisal/evidence.go new file mode 100644 index 00000000..6fa4a55e --- /dev/null +++ b/vts/appraisal/evidence.go @@ -0,0 +1,33 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package appraisal + +import "github.com/veraison/services/proto" + +// Evidence tracks the context of the evidence submmited for attestation. +type Evidence struct { + TenantID string `json:"tenant-id"` + Data []byte `json:"data"` + MediaType string `json:"media-type"` + Nonce []byte `json:"nonce"` +} + +// NewEvidenceFromProtobuf creates a new Evidence from a proto.AttestationToken +func NewEvidenceFromProtobuf(token *proto.AttestationToken) *Evidence { + return &Evidence{ + TenantID: token.TenantId, + Data: token.Data, + MediaType: token.MediaType, + Nonce: token.Nonce, + } +} + +// ToProtobuf converts this Evidence to an proto.AttestationToken +func (o *Evidence) ToProtobuf() *proto.AttestationToken { + return &proto.AttestationToken{ + TenantId: o.TenantID, + Data: o.Data, + MediaType: o.MediaType, + Nonce: o.Nonce, + } +} diff --git a/vts/cmd/vts-service/config-docker.yaml b/vts/cmd/vts-service/config-docker.yaml index 801f256d..d034242f 100644 --- a/vts/cmd/vts-service/config-docker.yaml +++ b/vts/cmd/vts-service/config-docker.yaml @@ -1,17 +1,14 @@ # This config file assumes the service is being run via "debug" command # from the docker deployment debug shell. plugin: - backend: builtin -ta-store: - backend: sql - sql: - driver: sqlite3 - datasource: /veraison/stores/vts/ta-store.sql -en-store: - backend: sql - sql: - driver: sqlite3 - datasource: /veraison/stores/vts/en-store.sql + #backend: builtin + backend: go-plugin + go-plugin: + dir: ../../../scheme/bin/ +store: + dbms: sqlite3 + dsn: file:/veraison/stores/vts/store.sql + trace-sql: false po-store: backend: sql sql: diff --git a/vts/cmd/vts-service/config.yaml b/vts/cmd/vts-service/config.yaml index ac8f2860..15b9e9f8 100644 --- a/vts/cmd/vts-service/config.yaml +++ b/vts/cmd/vts-service/config.yaml @@ -5,21 +5,15 @@ plugin: backend: go-plugin go-plugin: dir: ../../../scheme/bin/ -ta-store: - backend: sql - sql: - driver: sqlite3 - datasource: /tmp/ta-store.sql -en-store: - backend: sql - sql: - driver: sqlite3 - datasource: /tmp/en-store.sql po-store: backend: sql sql: driver: sqlite3 datasource: /tmp/po-store.sql +store: + dbms: sqlite3 + dsn: file::memory:?cache=shared + trace-sql: false po-agent: backend: opa vts: diff --git a/vts/cmd/vts-service/main.go b/vts/cmd/vts-service/main.go index fd507922..67f84f47 100644 --- a/vts/cmd/vts-service/main.go +++ b/vts/cmd/vts-service/main.go @@ -1,4 +1,4 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package main @@ -13,13 +13,13 @@ import ( "github.com/veraison/services/builtin" "github.com/veraison/services/config" "github.com/veraison/services/handler" - "github.com/veraison/services/kvstore" "github.com/veraison/services/log" "github.com/veraison/services/plugin" "github.com/veraison/services/policy" "github.com/veraison/services/vts/coservsigner" "github.com/veraison/services/vts/earsigner" "github.com/veraison/services/vts/policymanager" + "github.com/veraison/services/vts/store" "github.com/veraison/services/vts/trustedservices" ) @@ -31,24 +31,19 @@ func main() { log.Fatalf("could not read config: %v", err) } - subs, err := config.GetSubs(v, "ta-store", "en-store", "po-store", + subs, err := config.GetSubs(v, "store", "po-store", "*po-agent", "plugin", "*vts", "ear-signer", "*coserv-signer", "*logging") if err != nil { log.Fatal(err) } - classifiers := map[string]interface{}{"service": "vts"} + classifiers := map[string]any{"service": "vts"} if err := log.Init(subs["logging"], classifiers); err != nil { log.Fatalf("could not configure logging: %v", err) } log.Info("initializing stores") - taStore, err := kvstore.New(subs["ta-store"], log.Named("ta-store")) - if err != nil { - log.Fatalf("trust anchor store initialisation failed: %v", err) - } - - enStore, err := kvstore.New(subs["en-store"], log.Named("en-store")) + enStore, err := store.New(subs["store"], log.Named("store")) if err != nil { log.Fatalf("endorsement store initialization failed: %v", err) } @@ -65,16 +60,16 @@ func main() { } log.Info("loading attestation schemes") - var evPluginManager plugin.IManager[handler.IEvidenceHandler] - var endPluginManager plugin.IManager[handler.IEndorsementHandler] - var storePluginManager plugin.IManager[handler.IStoreHandler] + var schemePluginManager plugin.IManager[handler.ISchemeHandler] var coservProxyPluginManager plugin.IManager[handler.ICoservProxyHandler] psubs, err := config.GetSubs(subs["plugin"], "*go-plugin", "*builtin") if err != nil { log.Fatalf("could not get subs: %v", err) } - if config.SchemeLoader == "plugins" { // nolint:gocritic + + switch config.SchemeLoader { + case "plugins": loader, err := plugin.CreateGoPluginLoader( psubs["go-plugin"].AllSettings(), log.Named("plugin")) @@ -82,27 +77,11 @@ func main() { log.Fatalf("could not create plugin loader: %v", err) } - evPluginManager, err = plugin.CreateGoPluginManagerWithLoader( - loader, - "evidence-handler", - log.Named("plugin"), - handler.EvidenceHandlerRPC) - if err != nil { - log.Fatalf("could not create evidence PluginManagerWithLoader: %v", err) - } - endPluginManager, err = plugin.CreateGoPluginManagerWithLoader( - loader, - "endorsement-handler", - log.Named("plugin"), - handler.EndorsementHandlerRPC) - if err != nil { - log.Fatalf("could not create endorsement PluginManagerWithLoader: %v", err) - } - storePluginManager, err = plugin.CreateGoPluginManagerWithLoader( + schemePluginManager, err = plugin.CreateGoPluginManagerWithLoader( loader, - "store-handler", + "scheme-handler", log.Named("plugin"), - handler.StoreHandlerRPC) + handler.SchemeHandlerRPC) if err != nil { log.Fatalf("could not create store PluginManagerWithLoader: %v", err) } @@ -114,28 +93,16 @@ func main() { if err != nil { log.Fatalf("could not create coserv PluginManagerWithLoader: %v", err) } - } else if config.SchemeLoader == "builtin" { + case "builtin": loader, err := builtin.CreateBuiltinLoader( psubs["builtin"].AllSettings(), log.Named("builtin")) if err != nil { log.Fatalf("could not create builtin loader: %v", err) } - evPluginManager, err = builtin.CreateBuiltinManagerWithLoader[handler.IEvidenceHandler]( - loader, log.Named("builtin"), - "evidence-handler") - if err != nil { - log.Fatalf("could not create evidence BuiltinManagerWithLoader: %v", err) - } - endPluginManager, err = builtin.CreateBuiltinManagerWithLoader[handler.IEndorsementHandler]( - loader, log.Named("builtin"), - "endorsement-handler") - if err != nil { - log.Fatalf("could not create endorsement BuiltinManagerWithLoader: %v", err) - } - storePluginManager, err = builtin.CreateBuiltinManagerWithLoader[handler.IStoreHandler]( + schemePluginManager, err = builtin.CreateBuiltinManagerWithLoader[handler.ISchemeHandler]( loader, log.Named("builtin"), - "store-handler") + "scheme-handler") if err != nil { log.Fatalf("could not create store BuiltinManagerWithLoader: %v", err) } @@ -145,17 +112,17 @@ func main() { if err != nil { log.Fatalf("could not create coserv BuiltinManagerWithLoader: %v", err) } - } else { + default: log.Panicw("invalid SchemeLoader value", "SchemeLoader", config.SchemeLoader) } - log.Info("Evidence media types:") - for _, mt := range evPluginManager.GetRegisteredMediaTypes() { + log.Info("Provisioning media types:") + for _, mt := range schemePluginManager.GetRegisteredMediaTypesByCategory("provisioning") { log.Info("\t", mt) } - log.Info("Endorsement media types:") - for _, mt := range endPluginManager.GetRegisteredMediaTypes() { + log.Info("Verification media types:") + for _, mt := range schemePluginManager.GetRegisteredMediaTypesByCategory("verification") { log.Info("\t", mt) } @@ -187,11 +154,11 @@ func main() { // from this point onwards taStore, enStore, evPluginManager, // endPluginManager, storePluginManager, coservProxyPluginManager, // policyManager and earSigner are owned by vts - vts := trustedservices.NewGRPC(taStore, enStore, - evPluginManager, endPluginManager, storePluginManager, coservProxyPluginManager, + vts := trustedservices.NewGRPC(enStore, + schemePluginManager, coservProxyPluginManager, policyManager, earSigner, coservSigner, log.Named("vts")) - if err = vts.Init(subs["vts"], evPluginManager, endPluginManager, storePluginManager, coservProxyPluginManager); err != nil { + if err = vts.Init(subs["vts"]); err != nil { log.Fatalf("VTS initialisation failed: %v", err) } diff --git a/vts/coservsigner/coservsigner_cose_test.go b/vts/coservsigner/coservsigner_cose_test.go index 52cedb5b..e826827a 100644 --- a/vts/coservsigner/coservsigner_cose_test.go +++ b/vts/coservsigner/coservsigner_cose_test.go @@ -1,3 +1,5 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 package coservsigner import ( diff --git a/vts/earsigner/earsigner_jwt.go b/vts/earsigner/earsigner_jwt.go index ef90d8cc..99804c1f 100644 --- a/vts/earsigner/earsigner_jwt.go +++ b/vts/earsigner/earsigner_jwt.go @@ -1,4 +1,4 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package earsigner @@ -6,8 +6,8 @@ import ( "fmt" "strings" - "github.com/lestrrat-go/jwx/v2/jwa" - "github.com/lestrrat-go/jwx/v2/jwk" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" "github.com/veraison/ear" ) @@ -70,7 +70,7 @@ func algList() string { var l []string for _, a := range jwa.SignatureAlgorithms() { - l = append(l, string(a)) + l = append(l, a.String()) } return strings.Join(l, ", ") diff --git a/vts/earsigner/iearsigner.go b/vts/earsigner/iearsigner.go index 62b26105..60c2ff93 100644 --- a/vts/earsigner/iearsigner.go +++ b/vts/earsigner/iearsigner.go @@ -1,10 +1,10 @@ -// Copyright 2023-2025 Contributors to the Veraison project. +// Copyright 2023-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package earsigner import ( - "github.com/lestrrat-go/jwx/v2/jwa" - "github.com/lestrrat-go/jwx/v2/jwk" + "github.com/lestrrat-go/jwx/v3/jwa" + "github.com/lestrrat-go/jwx/v3/jwk" "github.com/veraison/ear" ) diff --git a/vts/earsigner/keyloader.go b/vts/earsigner/keyloader.go index 05a6f8a5..eaaff883 100644 --- a/vts/earsigner/keyloader.go +++ b/vts/earsigner/keyloader.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package earsigner @@ -18,7 +18,7 @@ func NewKeyLoader(fs afero.Fs) *KeyLoader { return &KeyLoader{ loaders: map[string]IKeyLoader{ "file": NewFileKeyLoader(fs), - "aws": NewAwsKeyLoader(context.TODO()), + "aws": NewAwsKeyLoader(context.TODO()), }, } } @@ -29,7 +29,7 @@ func (o KeyLoader) Load(location *url.URL) ([]byte, error) { if location.Scheme == "" { scheme = "file" } else { - scheme = location.Scheme + scheme = location.Scheme } actualLoader, ok := o.loaders[scheme] diff --git a/vts/earsigner/keyloader_aws.go b/vts/earsigner/keyloader_aws.go index 49f9987e..d6513498 100644 --- a/vts/earsigner/keyloader_aws.go +++ b/vts/earsigner/keyloader_aws.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package earsigner @@ -24,7 +24,9 @@ func NewAwsKeyLoader(c context.Context) *AwsKeyLoader { } // Load the key from the specified URL. The url must be in the following format: -// aws:/ +// +// aws:/ +// // Where is the AWS region (e.g. eu-west-1), and is the // name under which the key is stored in the AWS Secrets Manager func (o AwsKeyLoader) Load(location *url.URL) ([]byte, error) { @@ -42,7 +44,7 @@ func (o AwsKeyLoader) Load(location *url.URL) ([]byte, error) { client := secretsmanager.NewFromConfig(config) input := &secretsmanager.GetSecretValueInput{ - SecretId: aws.String(name), + SecretId: aws.String(name), VersionStage: aws.String("AWSCURRENT"), } diff --git a/vts/earsigner/keyloader_file.go b/vts/earsigner/keyloader_file.go index a862f4bc..b726f414 100644 --- a/vts/earsigner/keyloader_file.go +++ b/vts/earsigner/keyloader_file.go @@ -1,4 +1,4 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package earsigner @@ -20,8 +20,10 @@ func NewFileKeyLoader(fs afero.Fs) *FileKeyLoader { } // Load they key from the specified URL. The url must be in one of the following formats: -// -// file: +// +// +// file: +// // Where is the abosute path to the file contianing the key. func (o FileKeyLoader) Load(location *url.URL) ([]byte, error) { b, err := afero.ReadFile(o.fs, location.Path) diff --git a/vts/policymanager/mocks/iagent.go b/vts/policymanager/mocks/iagent.go index f3f160bb..ce37457b 100644 --- a/vts/policymanager/mocks/iagent.go +++ b/vts/policymanager/mocks/iagent.go @@ -10,9 +10,10 @@ import ( gomock "github.com/golang/mock/gomock" viper "github.com/spf13/viper" + comid "github.com/veraison/corim/comid" ear "github.com/veraison/ear" policy "github.com/veraison/services/policy" - proto "github.com/veraison/services/proto" + appraisal "github.com/veraison/services/vts/appraisal" ) // MockIAgent is a mock of IAgent interface. @@ -51,18 +52,18 @@ func (mr *MockIAgentMockRecorder) Close() *gomock.Call { } // Evaluate mocks base method. -func (m *MockIAgent) Evaluate(ctx context.Context, appraisalContext map[string]interface{}, scheme string, policy *policy.Policy, submod string, appraisal *ear.Appraisal, evidence *proto.EvidenceContext, endorsements []string) (*ear.Appraisal, error) { +func (m *MockIAgent) Evaluate(ctx context.Context, sessionContext map[string]any, appraisalContext *appraisal.Context, policy *policy.Policy, submod string, appraisal *ear.Appraisal, endorsements []*comid.ValueTriple) (*ear.Appraisal, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Evaluate", ctx, appraisalContext, scheme, policy, submod, appraisal, evidence, endorsements) + ret := m.ctrl.Call(m, "Evaluate", ctx, sessionContext, appraisalContext, policy, submod, appraisal, endorsements) ret0, _ := ret[0].(*ear.Appraisal) ret1, _ := ret[1].(error) return ret0, ret1 } // Evaluate indicates an expected call of Evaluate. -func (mr *MockIAgentMockRecorder) Evaluate(ctx, appraisalContext, scheme, policy, submod, appraisal, evidence, endorsements interface{}) *gomock.Call { +func (mr *MockIAgentMockRecorder) Evaluate(ctx, sessionContext, appraisalContext, policy, submod, appraisal, endorsements interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Evaluate", reflect.TypeOf((*MockIAgent)(nil).Evaluate), ctx, appraisalContext, scheme, policy, submod, appraisal, evidence, endorsements) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Evaluate", reflect.TypeOf((*MockIAgent)(nil).Evaluate), ctx, sessionContext, appraisalContext, policy, submod, appraisal, endorsements) } // GetBackendName mocks base method. diff --git a/vts/policymanager/mocks/ibackend.go b/vts/policymanager/mocks/ibackend.go index e95eb1d2..b11315eb 100644 --- a/vts/policymanager/mocks/ibackend.go +++ b/vts/policymanager/mocks/ibackend.go @@ -48,10 +48,10 @@ func (mr *MockIBackendMockRecorder) Close() *gomock.Call { } // Evaluate mocks base method. -func (m *MockIBackend) Evaluate(ctx context.Context, sessionContext map[string]interface{}, scheme, policy string, result, evidence map[string]interface{}, endorsements []string) (map[string]interface{}, error) { +func (m *MockIBackend) Evaluate(ctx context.Context, sessionContext map[string]any, scheme, policy string, result, evidence map[string]any, endorsements []map[string]any) (map[string]any, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Evaluate", ctx, sessionContext, scheme, policy, result, evidence, endorsements) - ret0, _ := ret[0].(map[string]interface{}) + ret0, _ := ret[0].(map[string]any) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/vts/policymanager/policymanager.go b/vts/policymanager/policymanager.go index 7b013c4c..e3e64949 100644 --- a/vts/policymanager/policymanager.go +++ b/vts/policymanager/policymanager.go @@ -1,4 +1,4 @@ -// Copyright 2022-2024 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policymanager @@ -7,6 +7,7 @@ import ( "errors" "github.com/spf13/viper" + "github.com/veraison/corim/comid" "github.com/veraison/services/policy" "github.com/veraison/services/vts/appraisal" "go.uber.org/zap" @@ -34,11 +35,10 @@ func New(v *viper.Viper, store *policy.Store, logger *zap.SugaredLogger) (*Polic func (o *PolicyManager) Evaluate( ctx context.Context, - scheme string, - appraisal *appraisal.Appraisal, - endorsements []string, + appraisalContext *appraisal.Context, + endorsements []*comid.ValueTriple, ) error { - policyKey := o.getPolicyKey(appraisal) + policyKey := o.getPolicyKey(appraisalContext) pol, err := o.getPolicy(policyKey) if err != nil { @@ -50,36 +50,36 @@ func (o *PolicyManager) Evaluate( return err } - appraisalContext := map[string]interface{}{ - "nonce": appraisal.Result.Nonce, + sessionContext := map[string]any{ + "nonce": appraisalContext.Result.Nonce, } - for submod, submodAppraisal := range appraisal.Result.Submods { + for submodName, submodAppraisal := range appraisalContext.Result.Submods { evaluated, err := o.Agent.Evaluate( ctx, + sessionContext, appraisalContext, - scheme, pol, - submod, + submodName, submodAppraisal, - appraisal.EvidenceContext, endorsements, ) if err != nil { return err } - appraisal.Result.Submods[submod] = evaluated + appraisalContext.Result.Submods[submodName] = evaluated } - if err := appraisal.UpdatePolicyID(pol); err != nil { + + if err := appraisalContext.UpdatePolicyID(pol.UUID.String()); err != nil { return err } return nil } -func (o *PolicyManager) getPolicyKey(a *appraisal.Appraisal) policy.PolicyKey { +func (o *PolicyManager) getPolicyKey(a *appraisal.Context) policy.PolicyKey { return policy.PolicyKey{ - TenantId: a.EvidenceContext.TenantId, + TenantId: a.Evidence.TenantID, Scheme: a.Scheme, Name: o.Agent.GetBackendName(), } diff --git a/vts/policymanager/policymanager_test.go b/vts/policymanager/policymanager_test.go index 7ccd15e4..a24602dd 100644 --- a/vts/policymanager/policymanager_test.go +++ b/vts/policymanager/policymanager_test.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package policymanager @@ -11,14 +11,13 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/veraison/corim/comid" "github.com/veraison/ear" "github.com/veraison/services/kvstore" "github.com/veraison/services/log" "github.com/veraison/services/policy" - "github.com/veraison/services/proto" "github.com/veraison/services/vts/appraisal" mock_deps "github.com/veraison/services/vts/policymanager/mocks" - "google.golang.org/protobuf/types/known/structpb" ) func TestPolicyMgr_getPolicy_not_found(t *testing.T) { @@ -32,16 +31,11 @@ func TestPolicyMgr_getPolicy_not_found(t *testing.T) { // Get the Mock Agent here agent := mock_deps.NewMockIAgent(ctrl) agent.EXPECT().GetBackendName().Return("opa") - evStruct, err := structpb.NewStruct(nil) - require.NoError(t, err) - appraisal := &appraisal.Appraisal{ + appraisal := &appraisal.Context{ Scheme: "TPM_ENACTTRUST", - EvidenceContext: &proto.EvidenceContext{ - TenantId: "0", - TrustAnchorIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - ReferenceIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - Evidence: evStruct, + Evidence: &appraisal.Evidence{ + TenantID: "0", }, } @@ -67,16 +61,10 @@ func TestPolicyMgr_getPolicy_OK(t *testing.T) { agent := mock_deps.NewMockIAgent(ctrl) agent.EXPECT().GetBackendName().Return("opa") - evStruct, err := structpb.NewStruct(nil) - require.NoError(t, err) - - appraisal := &appraisal.Appraisal{ + appraisal := &appraisal.Context{ Scheme: "TPM_ENACTTRUST", - EvidenceContext: &proto.EvidenceContext{ - TenantId: "0", - TrustAnchorIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - ReferenceIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - Evidence: evStruct, + Evidence: &appraisal.Evidence{ + TenantID: "0", }, } @@ -85,7 +73,7 @@ func TestPolicyMgr_getPolicy_OK(t *testing.T) { polKey := pm.getPolicyKey(appraisal) assert.Equal(t, "0:TPM_ENACTTRUST:opa", polKey.String()) - _, err = pm.getPolicy(polKey) + _, err := pm.getPolicy(polKey) require.NoError(t, err) } @@ -113,78 +101,85 @@ func TestPolicyMgr_New_policyAgent_NOK(t *testing.T) { func TestPolicyMgr_Evaluate_OK(t *testing.T) { ctrl := gomock.NewController(t) - evStruct, _ := structpb.NewStruct(nil) + + polID := "policy:TPM_ENACTTRUST" + endorsements := []*comid.ValueTriple{} + ar := ear.NewAttestationResult("test", "test", "test") + tier := ear.TrustTierAffirming + earAp := ear.Appraisal{Status: &tier, AppraisalPolicyID: &polID} + appraisalContext := &appraisal.Context{ + Scheme: "TPM_ENACTTRUST", + Evidence: &appraisal.Evidence{ + TenantID: "0", + }, + Result: ar, + } store := mock_deps.NewMockIKVStore(ctrl) store.EXPECT(). Get(gomock.Eq("0:TPM_ENACTTRUST:opa")). Return([]string{`{"uuid": "7df7714e-aa04-4638-bcbf-434b1dd720f1", "active": true}`}, nil) - ec := &proto.EvidenceContext{ - TenantId: "0", - TrustAnchorIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - ReferenceIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - Evidence: evStruct, - } - endorsements := []string{"h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc="} - ar := ear.NewAttestationResult("test", "test", "test") - ap := &appraisal.Appraisal{EvidenceContext: ec, Result: ar, Scheme: "TPM_ENACTTRUST"} - - polID := "policy:TPM_ENACTTRUST" - tier := ear.TrustTierAffirming - earAp := ear.Appraisal{Status: &tier, AppraisalPolicyID: &polID} - agent := mock_deps.NewMockIAgent(ctrl) agent.EXPECT().GetBackendName().Return("opa") agent.EXPECT(). Evaluate( context.TODO(), gomock.Any(), - "test", - gomock.Any(), + appraisalContext, gomock.Any(), + "test", ar.Submods["test"], - ec, endorsements, ). Return(&earAp, nil) + pm := &PolicyManager{ Store: &policy.Store{KVStore: store, Logger: log.Named("store")}, Agent: agent, logger: log.Named("manager"), } - err := pm.Evaluate(context.TODO(), "test", ap, endorsements) + err := pm.Evaluate(context.TODO(), appraisalContext, endorsements) require.NoError(t, err) } func TestPolicyMgr_Evaluate_NOK(t *testing.T) { ctrl := gomock.NewController(t) - evStruct, _ := structpb.NewStruct(nil) store := mock_deps.NewMockIKVStore(ctrl) store.EXPECT(). Get(gomock.Eq("0:TPM_ENACTTRUST:opa")). Return([]string{`{"uuid": "7df7714e-aa04-4638-bcbf-434b1dd720f1", "active": true}`}, nil) - ec := &proto.EvidenceContext{ - TenantId: "0", - TrustAnchorIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - ReferenceIds: []string{"TPM_ENACTTRUST://0/7df7714e-aa04-4638-bcbf-434b1dd720f1"}, - Evidence: evStruct, - } - endorsements := []string{"h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc="} ar := ear.NewAttestationResult("test", "test", "test") - ap := &appraisal.Appraisal{EvidenceContext: ec, Result: ar, Scheme: "TPM_ENACTTRUST"} expectedErr := errors.New("could not evaluate policy: policy returned bad update") agent := mock_deps.NewMockIAgent(ctrl) agent.EXPECT().GetBackendName().Return("opa") - agent.EXPECT().Evaluate(context.TODO(), gomock.Any(), "test", gomock.Any(), gomock.Any(), ar.Submods["test"], ec, endorsements).Return(nil, expectedErr) + endorsements := []*comid.ValueTriple{} + appraisalContext := &appraisal.Context{ + Scheme: "TPM_ENACTTRUST", + Evidence: &appraisal.Evidence{ + TenantID: "0", + }, + Result: ar, + } + + agent.EXPECT().Evaluate( + context.TODO(), + gomock.Any(), + appraisalContext, + gomock.Any(), + "test", + ar.Submods["test"], + endorsements, + ).Return(nil, expectedErr) + pm := &PolicyManager{ Store: &policy.Store{KVStore: store, Logger: log.Named("store")}, Agent: agent, logger: log.Named("manager"), } - err := pm.Evaluate(context.TODO(), "test", ap, endorsements) + err := pm.Evaluate(context.TODO(), appraisalContext, endorsements) assert.ErrorIs(t, err, expectedErr) } diff --git a/vts/store/store.go b/vts/store/store.go new file mode 100644 index 00000000..c7af2806 --- /dev/null +++ b/vts/store/store.go @@ -0,0 +1,57 @@ +// Copyright 2025-2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package store + +import ( + "context" + "strings" + + "github.com/spf13/viper" + corimstore "github.com/veraison/corim-store/pkg/store" + "github.com/veraison/services/config" + "go.uber.org/zap" +) + +type Config struct { + DBMS string `mapstructure:"dbms"` + DSN string `mapstructure:"dsn"` + TraceSQL bool `mapstructure:"trace-sql" config:"zerodefault"` +} + +func (o *Config) StoreConfig() *corimstore.Config { + ret := corimstore.NewConfig(o.DBMS, o.DSN, corimstore.OptionRequireLabel) + + if o.TraceSQL { + ret.WithOptions(corimstore.OptionTraceSQL) + } + + return ret +} + +func New(v *viper.Viper, logger *zap.SugaredLogger) (*corimstore.Store, error) { + var cfg Config + + loader := config.NewLoader(&cfg) + if err := loader.LoadFromViper(v); err != nil { + return nil, err + } + + logger.Debugf("connecting to %s store %s", cfg.DBMS, cfg.DSN) + + store, err := corimstore.Open(context.Background(), cfg.StoreConfig()) + if err != nil { + return nil, err + } + + // The store must be innitialized before it may be used. In general, we + // rely on the store being pointed to by DSN to be innitialized prior + // to starting the VTS. For in-memory store this can never be the case, so we + // initialize it here. + if strings.Contains(cfg.DSN, ":memory:") { + if err := store.Init(); err != nil { + return nil, err + } + } + + return store, nil +} diff --git a/vts/trustedservices/itrustedservices.go b/vts/trustedservices/itrustedservices.go index b9d995c6..8788fb7e 100644 --- a/vts/trustedservices/itrustedservices.go +++ b/vts/trustedservices/itrustedservices.go @@ -1,22 +1,14 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package trustedservices import ( "github.com/spf13/viper" - "github.com/veraison/services/handler" - "github.com/veraison/services/plugin" "github.com/veraison/services/proto" ) type ITrustedServices interface { - Init( - cfg *viper.Viper, - evidenceManager plugin.IManager[handler.IEvidenceHandler], - endorsementManager plugin.IManager[handler.IEndorsementHandler], - storeManager plugin.IManager[handler.IStoreHandler], - coservProxyManager plugin.IManager[handler.ICoservProxyHandler], - ) error + Init(cfg *viper.Viper) error Close() error Run() error diff --git a/vts/trustedservices/trustedservices_grpc.go b/vts/trustedservices/trustedservices_grpc.go index 49c11095..0f517659 100644 --- a/vts/trustedservices/trustedservices_grpc.go +++ b/vts/trustedservices/trustedservices_grpc.go @@ -1,4 +1,4 @@ -// Copyright 2022-2025 Contributors to the Veraison project. +// Copyright 2022-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package trustedservices @@ -14,6 +14,7 @@ import ( "net" "os" "strings" + "time" "github.com/spf13/viper" "go.uber.org/zap" @@ -22,12 +23,14 @@ import ( "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/structpb" + "github.com/veraison/corim-store/pkg/model" + corimstore "github.com/veraison/corim-store/pkg/store" + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" "github.com/veraison/corim/coserv" "github.com/veraison/ear" "github.com/veraison/services/config" - "github.com/veraison/services/handler" handlermod "github.com/veraison/services/handler" - "github.com/veraison/services/kvstore" "github.com/veraison/services/plugin" "github.com/veraison/services/proto" "github.com/veraison/services/vts/appraisal" @@ -41,6 +44,8 @@ import ( // should be passed as a parameter const DummyTenantID = "0" +var ErrMeasurementsNotSupported = errors.New("measurements in CoSERV queries are not supported") + // Supported parameters: // // - vts.server-addr: string w/ syntax specified in @@ -64,16 +69,13 @@ func NewGRPCConfig() *GRPCConfig { type GRPC struct { ServerAddress string - TaStore kvstore.IKVStore - EnStore kvstore.IKVStore - EvPluginManager plugin.IManager[handler.IEvidenceHandler] - EndPluginManager plugin.IManager[handler.IEndorsementHandler] - StorePluginManager plugin.IManager[handler.IStoreHandler] - CoservProxyPluginManager plugin.IManager[handler.ICoservProxyHandler] + Store *corimstore.Store + SchemePluginManager plugin.IManager[handlermod.ISchemeHandler] + CoservProxyPluginManager plugin.IManager[handlermod.ICoservProxyHandler] PolicyManager *policymanager.PolicyManager EarSigner earsigner.IEarSigner CoservSigner coservsigner.ICoservSigner - CACertsPEM [][]byte + rootCerts *x509.CertPool Server *grpc.Server Socket net.Listener @@ -84,22 +86,17 @@ type GRPC struct { } func NewGRPC( - taStore, enStore kvstore.IKVStore, - evidencePluginManager plugin.IManager[handler.IEvidenceHandler], - endorsementPluginManager plugin.IManager[handler.IEndorsementHandler], - storePluginManager plugin.IManager[handler.IStoreHandler], - coservProxyPluginManager plugin.IManager[handler.ICoservProxyHandler], + store *corimstore.Store, + schemePluginManager plugin.IManager[handlermod.ISchemeHandler], + coservProxyPluginManager plugin.IManager[handlermod.ICoservProxyHandler], policyManager *policymanager.PolicyManager, earSigner earsigner.IEarSigner, coservSigner coservsigner.ICoservSigner, logger *zap.SugaredLogger, ) ITrustedServices { return &GRPC{ - TaStore: taStore, - EnStore: enStore, - EvPluginManager: evidencePluginManager, - EndPluginManager: endorsementPluginManager, - StorePluginManager: storePluginManager, + Store: store, + SchemePluginManager: schemePluginManager, CoservProxyPluginManager: coservProxyPluginManager, PolicyManager: policyManager, EarSigner: earSigner, @@ -119,10 +116,6 @@ func (o *GRPC) Run() error { func (o *GRPC) Init( v *viper.Viper, - evidenceManager plugin.IManager[handler.IEvidenceHandler], - endorsementManager plugin.IManager[handler.IEndorsementHandler], - storeManager plugin.IManager[handler.IStoreHandler], - coservProxyManager plugin.IManager[handler.ICoservProxyHandler], ) error { var err error @@ -136,11 +129,6 @@ func (o *GRPC) Init( return err } - o.EvPluginManager = evidenceManager - o.EndPluginManager = endorsementManager - o.StorePluginManager = storeManager - o.CoservProxyPluginManager = coservProxyManager - if cfg.ListenAddress != "" { o.ServerAddress = cfg.ListenAddress } else { @@ -155,17 +143,11 @@ func (o *GRPC) Init( var opts []grpc.ServerOption - var certsPEM [][]byte - if len(cfg.CACerts) > 0 { - var err error - certsPEM, err = LoadCACerts(cfg.CACerts) - if err != nil { - return err - } - } else { - certsPEM = [][]byte{} + o.logger.Info("loading root CA certs") + o.rootCerts, err = LoadCACerts(cfg.CACerts) + if err != nil { + return err } - o.CACertsPEM = certsPEM if cfg.UseTLS { o.logger.Info("loading TLS credentials") @@ -191,28 +173,16 @@ func (o *GRPC) Close() error { o.Server.GracefulStop() } - if err := o.EvPluginManager.Close(); err != nil { - o.logger.Errorf("evidence plugin manager shutdown failed: %v", err) - } - - if err := o.EndPluginManager.Close(); err != nil { - o.logger.Errorf("endorsement plugin manager shutdown failed: %v", err) - } - - if err := o.StorePluginManager.Close(); err != nil { - o.logger.Errorf("store plugin manager shutdown failed: %v", err) + if err := o.SchemePluginManager.Close(); err != nil { + o.logger.Errorf("scheme plugin manager shutdown failed: %v", err) } if err := o.CoservProxyPluginManager.Close(); err != nil { o.logger.Errorf("coserv plugin manager shutdown failed: %v", err) } - if err := o.TaStore.Close(); err != nil { - o.logger.Errorf("trust anchor store closure failed: %v", err) - } - - if err := o.EnStore.Close(); err != nil { - o.logger.Errorf("endorsement store closure failed: %v", err) + if err := o.Store.Close(); err != nil { + o.logger.Errorf("store closure failed: %v", err) } if err := o.EarSigner.Close(); err != nil { @@ -229,7 +199,7 @@ func (o *GRPC) Close() error { } func (o *GRPC) GetServiceState(context.Context, *emptypb.Empty) (*proto.ServiceState, error) { - mediaTypes := o.EvPluginManager.GetRegisteredMediaTypes() + mediaTypes := o.SchemePluginManager.GetRegisteredMediaTypes() mediaTypesList, err := proto.NewStringList(mediaTypes) if err != nil { @@ -245,56 +215,75 @@ func (o *GRPC) GetServiceState(context.Context, *emptypb.Empty) (*proto.ServiceS }, nil } -func (o *GRPC) SubmitEndorsements(ctx context.Context, req *proto.SubmitEndorsementsRequest) (*proto.SubmitEndorsementsResponse, error) { +func (o *GRPC) SubmitEndorsements( + ctx context.Context, + req *proto.SubmitEndorsementsRequest, +) (*proto.SubmitEndorsementsResponse, error) { o.logger.Debugw("SubmitEndorsements", "media-type", req.MediaType) - handlerPlugin, err := o.EndPluginManager.LookupByMediaType(req.MediaType) + mt, mtParams, err := mime.ParseMediaType(req.MediaType) if err != nil { return nil, err } + profile := mtParams["profile"] - // Serialize the CA cert pool for transmission if it's a signed CoRIM - var caCertPoolBytes []byte - mt, _, err := mime.ParseMediaType(req.MediaType) - if err != nil { - return nil, err - } - if mt == "application/rim+cose" && len(o.CACertsPEM) != 0 { - var err error - caCertPoolBytes, err = SerializeCertPEMBytes(o.CACertsPEM) + var uc *corim.UnsignedCorim + switch mt { + case "application/rim+cose": + uc, err = o.decodeAndValidateSignedCorim(req.Data) if err != nil { - return nil, err + return submitEndorsementErrorResponse(err), nil } + case "application/rim+cbor": + uc, err = o.decodeAndValidateUnsignedCorim(req.Data) + if err != nil { + return submitEndorsementErrorResponse(err), nil + } + default: + err = fmt.Errorf("unsupported media type: %s", req.MediaType) + return submitEndorsementErrorResponse(err), nil } - rsp, err := handlerPlugin.Decode(req.Data, req.MediaType, caCertPoolBytes) - if err != nil { - return submitEndorsementErrorResponse(err), nil + if uc.Profile == nil { + return nil, errors.New("profile not set in CoRIM") } - if err := o.storeEndorsements(ctx, rsp); err != nil { - return submitEndorsementErrorResponse(err), nil + + ucProfile, err := uc.Profile.Get() + if err != nil { + return nil, fmt.Errorf("invalid profile in CoRIM: %v", uc.Profile) } - return submitEndorsementSuccessResponse(), nil -} -func (o *GRPC) storeEndorsements(ctx context.Context, rsp *handler.EndorsementHandlerResponse) error { - for _, ta := range rsp.TrustAnchors { + o.logger.Debugw(" CoRIM profile", "profile", ucProfile) - err := o.addTrustAnchor(ctx, &ta) - if err != nil { - return fmt.Errorf("store operation failed for trust anchor: %w", err) - } + if ucProfile != profile { + err := fmt.Errorf( + "CoRIM profile (%s) does not match media type profile (%s)", + ucProfile, + profile, + ) + o.logger.Warn(err.Error()) + return nil, err } - for _, refVal := range rsp.ReferenceValues { + handlerPlugin, err := o.SchemePluginManager.LookupByMediaType(req.MediaType) + if err != nil { + return nil, err + } - err := o.addRefValues(ctx, &refVal) - if err != nil { - return fmt.Errorf("store operation failed for reference values: %w", err) - } + resp, err := handlerPlugin.ValidateCorim(uc) + if err != nil { + return nil, err + } else if !resp.IsValid { + return submitEndorsementErrorResponse(resp.Error()), nil } - return nil + label := fmt.Sprintf("%s/%s", DummyTenantID, handlerPlugin.GetAttestationScheme()) + digest := o.Store.Digest(req.Data) + if err := o.storeEndorsements(ctx, uc, label, digest); err != nil { + return submitEndorsementErrorResponse(err), nil + } + + return submitEndorsementSuccessResponse(), nil } func submitEndorsementSuccessResponse() *proto.SubmitEndorsementsResponse { @@ -314,84 +303,68 @@ func submitEndorsementErrorResponse(err error) *proto.SubmitEndorsementsResponse } } -func (o *GRPC) addRefValues(ctx context.Context, refVal *handler.Endorsement) error { - var ( - err error - keys []string - handler handler.IStoreHandler - val []byte - ) - - handler, err = o.StorePluginManager.LookupByAttestationScheme(refVal.Scheme) - if err != nil { - return err +func (o *GRPC) decodeAndValidateSignedCorim(data []byte) (*corim.UnsignedCorim, error) { + if len(data) == 0 { + return nil, fmt.Errorf("empty corim data") } - keys, err = handler.SynthKeysFromRefValue(DummyTenantID, refVal) + // Parse the signed CoRIM which extracts certificate chain automatically through extractX5Chain + sc, err := corim.UnmarshalAndValidateSignedCorimFromCBOR(data) if err != nil { - return err + return nil, fmt.Errorf("failed to parse signed CoRIM: %w", err) } - val, err = json.Marshal(refVal) - if err != nil { - return err + if sc.SigningCert == nil { + return nil, fmt.Errorf("no signing certificate found in the CoRIM") } - for _, key := range keys { - if err := o.EnStore.Add(key, string(val)); err != nil { - if err != nil { - return err - } - } + intermediateCertPool := x509.NewCertPool() + for _, cert := range sc.IntermediateCerts { + intermediateCertPool.AddCert(cert) } - o.logger.Infow("added reference values", "keys", keys) - - return nil -} - -func (o *GRPC) addTrustAnchor( - ctx context.Context, - req *handler.Endorsement, -) error { - var ( - err error - keys []string - handler handler.IStoreHandler - val []byte - ) - - o.logger.Debugw("AddTrustAnchor", "trust-anchor", req) - - if req == nil { - return errors.New("nil trust anchor in request") + // Verify the certificate chain with properly separated root and intermediate pools + verifyOpts := x509.VerifyOptions{ + Roots: o.rootCerts, + Intermediates: intermediateCertPool, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, } - handler, err = o.StorePluginManager.LookupByAttestationScheme(req.Scheme) + _, err = sc.SigningCert.Verify(verifyOpts) if err != nil { - return err + return nil, fmt.Errorf("certificate chain verification failed: %w", err) } - keys, err = handler.SynthKeysFromTrustAnchor(DummyTenantID, req) - if err != nil { - return err + // Verify the signature using the signing certificate's public key + if err := sc.Verify(sc.SigningCert.PublicKey); err != nil { + return nil, fmt.Errorf("signature verification failed: %w", err) } - val, err = json.Marshal(req) + return &sc.UnsignedCorim, nil +} + +func (o *GRPC) decodeAndValidateUnsignedCorim(data []byte) (*corim.UnsignedCorim, error) { + return corim.UnmarshalAndValidateUnsignedCorimFromCBOR(data) +} + +func (o *GRPC) storeEndorsements( + _ context.Context, + uc *corim.UnsignedCorim, + label string, + digest []byte, +) error { + manifest, err := model.NewManifestFromCoRIM(uc) if err != nil { return err } + manifest.Label = label + manifest.Digest = digest + manifest.SetActive(true) - for _, key := range keys { - if err := o.TaStore.Add(key, string(val)); err != nil { - if err != nil { - return err - } - } + if err := o.Store.AddManifest(manifest); err != nil { + return err } - o.logger.Infow("added trust anchor", "keys", keys) - return nil } @@ -399,94 +372,110 @@ func (o *GRPC) GetAttestation( ctx context.Context, token *proto.AttestationToken, ) (*proto.AppraisalContext, error) { - o.logger.Infow("get attestation", "media-type", token.MediaType, - "tenant-id", token.TenantId) + evidence := appraisal.NewEvidenceFromProtobuf(token) + o.logger.Infow("get attestation", "media-type", evidence.MediaType, + "tenant-id", evidence.TenantID) - handler, err := o.EvPluginManager.LookupByMediaType(token.MediaType) + appraisal := appraisal.NewContext(evidence) + + handler, err := o.SchemePluginManager.LookupByMediaType(evidence.MediaType) if err != nil { - appraisal := appraisal.New(token.TenantId, token.Nonce, "ERROR") appraisal.SetAllClaims(ear.UnexpectedEvidenceClaim) appraisal.AddPolicyClaim("problem", "could not resolve media type") return o.finalize(appraisal, err) } - scheme := handler.GetAttestationScheme() - stHandler, err := o.StorePluginManager.LookupByAttestationScheme(scheme) - if err != nil { - appraisal := appraisal.New(token.TenantId, token.Nonce, "ERROR") - appraisal.SetAllClaims(ear.UnexpectedEvidenceClaim) - appraisal.AddPolicyClaim("problem", "could not resolve scheme name") + if err := appraisal.SetScheme(handler.GetAttestationScheme()); err != nil { return o.finalize(appraisal, err) } - appraisal, err := o.initEvidenceContext(stHandler, token) + appraisal.TrustAnchorIDs, err = handler.GetTrustAnchorIDs(evidence) if err != nil { + if errors.Is(err, handlermod.BadEvidenceError{}) { + appraisal.SetAllClaims(ear.CryptoValidationFailedClaim) + appraisal.AddPolicyClaim("problem", "could not establish identity from evidence") + } + return o.finalize(appraisal, err) } - tas, err := o.getTrustAnchors(appraisal.EvidenceContext.TrustAnchorIds) - if err != nil { - if errors.Is(err, kvstore.ErrKeyNotFound) { - err = handlermod.BadEvidence("no trust anchor for %s", - appraisal.EvidenceContext.TrustAnchorIds) + // TODO(setrofim): in principle, we should be matching exactly + // here, as we are trying to identify triples for a specific + // entity described by the taID environment. However, CoRIM does + // not provide a good way to endorse an environment description. So + // in practice, environments inside CoRIMs may serve + // the double duty of providing a way to match measurements + // _and_ an additional description of the environments that is + // not present in the evidence. + // + // Specifically, our parsec-tpm scheme currently relies on the + // fact that the trust anchors are provisioned with environment + // that contains a class-id as well as an instance-id; the + // evidence only contains an instance-id, and the class-id in + // the trust anchor is then used to retrieve reference values; + // there is no way to directly link reference values to the + // evidence. + // + // Because provisioned environments may contain "additional" + // descriptive elements, as well as elements used for matching, + // we are forced to do inexact matching here for now, and leave + // it to the attestation schemes to resolve this. + matchExactly := false + trustAnchors, err := o.getKeyTriples(appraisal.TrustAnchorIDs, appraisal.StoreLabel(), matchExactly) + if err != nil { + if errors.Is(err, corimstore.ErrNoMatch) { + err = handlermod.BadEvidence("no trust anchor for %s", appraisal.DescribeTrustAnchorIDs()) appraisal.SetAllClaims(ear.CryptoValidationFailedClaim) appraisal.AddPolicyClaim("problem", "no trust anchor for evidence") } + return o.finalize(appraisal, err) } - claims, err := handler.ExtractClaims(token, tas) + claims, err := handler.ExtractClaims(appraisal.Evidence, trustAnchors) if err != nil { if errors.Is(err, handlermod.BadEvidenceError{}) { appraisal.AddPolicyClaim("problem", err.Error()) } return o.finalize(appraisal, err) } + appraisal.Claims = claims - referenceIDs, err := stHandler.GetRefValueIDs(token.TenantId, tas, claims) - if err != nil { - return o.finalize(appraisal, err) - } - - appraisal.EvidenceContext.Evidence, err = structpb.NewStruct(claims) + appraisal.ReferenceValueIDs, err = handler.GetReferenceValueIDs(trustAnchors, claims) if err != nil { - err = fmt.Errorf("unserializable claims in result: %w", err) return o.finalize(appraisal, err) } - appraisal.EvidenceContext.ReferenceIds = referenceIDs - o.logger.Debugw("constructed evidence context", - "software-id", appraisal.EvidenceContext.ReferenceIds, - "trust-anchor-id", appraisal.EvidenceContext.TrustAnchorIds) - - var multEndorsements []string - for _, refvalID := range appraisal.EvidenceContext.ReferenceIds { + "software-id", appraisal.ReferenceValueIDs, + "trust-anchor-id", appraisal.TrustAnchorIDs) - endorsements, err := o.EnStore.Get(refvalID) - if err != nil && !errors.Is(err, kvstore.ErrKeyNotFound) { - return o.finalize(appraisal, err) - } - - o.logger.Debugw("obtained endorsements", "endorsements", endorsements) - multEndorsements = append(multEndorsements, endorsements...) + o.logger.Debug("obtaining endorsements...") + endorsements, err := o.getValueTriples(appraisal.ReferenceValueIDs, appraisal.StoreLabel(), true) + if err != nil { + return o.finalize(appraisal, err) } - if err = handler.ValidateEvidenceIntegrity(token, tas, multEndorsements); err != nil { + o.logger.Debug("validating evidence...") + if err = handler.ValidateEvidenceIntegrity(appraisal.Evidence, trustAnchors, endorsements); err != nil { if errors.Is(err, handlermod.BadEvidenceError{}) { var badErr handlermod.BadEvidenceError + claimStr := "integrity validation failed" ok := errors.As(err, &badErr) if ok { claimStr += fmt.Sprintf(": %s", badErr.ToString()) } + appraisal.SetAllClaims(ear.CryptoValidationFailedClaim) appraisal.AddPolicyClaim("problem", claimStr) } + return o.finalize(appraisal, err) } - appraisedResult, err := handler.AppraiseEvidence(appraisal.EvidenceContext, multEndorsements) + o.logger.Debug("appraising claims...") + appraisedResult, err := handler.AppraiseClaims(claims, endorsements) if err != nil { return o.finalize(appraisal, err) } @@ -494,59 +483,61 @@ func (o *GRPC) GetAttestation( appraisal.Result = appraisedResult appraisal.InitPolicyID() - err = o.PolicyManager.Evaluate(ctx, handler.GetAttestationScheme(), appraisal, multEndorsements) + o.logger.Debug("evaluating policy...") + err = o.PolicyManager.Evaluate(ctx, appraisal, endorsements) if err != nil { return o.finalize(appraisal, err) } o.logger.Infow("evaluated attestation result", "attestation-result", appraisal.Result) - return o.finalize(appraisal, nil) } -func (c *GRPC) initEvidenceContext( - handler handler.IStoreHandler, - token *proto.AttestationToken, -) (*appraisal.Appraisal, error) { - var err error +func (o *GRPC) getKeyTriples( + trustAnchorIDs []*comid.Environment, + label string, + exact bool, +) ([]*comid.KeyTriple, error) { + var keyTriples []*comid.KeyTriple //nolint - appraisal := appraisal.New(token.TenantId, token.Nonce, handler.GetAttestationScheme()) - appraisal.EvidenceContext.TrustAnchorIds, err = handler.GetTrustAnchorIDs(token) + for _, taID := range trustAnchorIDs { + triples, err := o.Store.GetActiveKeyTriples(taID, label, exact) + if err != nil { + return nil, err + } - if errors.Is(err, handlermod.BadEvidenceError{}) { - appraisal.SetAllClaims(ear.CryptoValidationFailedClaim) - appraisal.AddPolicyClaim("problem", "could not establish identity from evidence") + keyTriples = append(keyTriples, triples...) } - return appraisal, err + return keyTriples, nil } -func (c *GRPC) getTrustAnchors(id []string) ([]string, error) { - var taValues []string //nolint +func (o *GRPC) getValueTriples( + referenceValueIDs []*comid.Environment, + label string, + exact bool, +) ([]*comid.ValueTriple, error) { + var valueTriples []*comid.ValueTriple //nolint - for _, taID := range id { - values, err := c.TaStore.Get(taID) - if err != nil { - return []string{""}, err + for _, valID := range referenceValueIDs { + triples, err := o.Store.GetActiveValueTriples(valID, label, exact) + if err != nil && !errors.Is(err, corimstore.ErrNoMatch) { + return nil, err } - // For now, Veraison schemes only support one trust anchor per trustAnchorID - if len(values) != 1 { - return []string{""}, fmt.Errorf("found %d trust anchors, want 1", len(values)) - } - taValues = append(taValues, values[0]) + valueTriples = append(valueTriples, triples...) } - return taValues, nil + return valueTriples, nil } func (c *GRPC) GetSupportedVerificationMediaTypes(context.Context, *emptypb.Empty) (*proto.MediaTypeList, error) { - mts := c.EvPluginManager.GetRegisteredMediaTypes() + mts := c.SchemePluginManager.GetRegisteredMediaTypesByCategory("verification") return &proto.MediaTypeList{MediaTypes: mts}, nil } func (c *GRPC) GetSupportedProvisioningMediaTypes(context.Context, *emptypb.Empty) (*proto.MediaTypeList, error) { - mts := c.EndPluginManager.GetRegisteredMediaTypes() + mts := c.SchemePluginManager.GetRegisteredMediaTypesByCategory("provisioning") return &proto.MediaTypeList{MediaTypes: mts}, nil } @@ -579,7 +570,7 @@ func (c *GRPC) GetSupportedCoservMediaTypes(context.Context, *emptypb.Empty) (*p var mediaTypes []string corimDerived := c.assembleCoservMediaTypes( - c.EndPluginManager.GetRegisteredMediaTypes(), + c.SchemePluginManager.GetRegisteredMediaTypesByCategory("provisioning"), "application/rim+cbor", ) @@ -657,80 +648,96 @@ func getEndorsementsError(err error) *proto.EndorsementQueryOut { } } -func (o *GRPC) getEndorsementsFromStores(query *proto.EndorsementQueryIn) ([]byte, error) { - var q coserv.Coserv - if err := q.FromBase64Url(query.Query); err != nil { +func (o *GRPC) getEndorsementsFromStores(queryIn *proto.EndorsementQueryIn) ([]byte, error) { + var query coserv.Coserv + if err := query.FromBase64Url(queryIn.Query); err != nil { return nil, err } - // select store based on the requested artefact type - var ( - store kvstore.IKVStore - storeName string - ) - switch q.Query.ArtifactType { - case coserv.ArtifactTypeEndorsedValues: - return nil, errors.New("endorsed value queries are not supported") - case coserv.ArtifactTypeReferenceValues: - storeName = "reference-value" - store = o.EnStore - case coserv.ArtifactTypeTrustAnchors: - storeName = "trust-anchors" - store = o.TaStore - } - - profile, err := q.Profile.Get() + profile, err := query.Profile.Get() if err != nil { return nil, err } // Look up a matching endorsement plugin - endorsementHandler, err := o.EndPluginManager.LookupByMediaType(fmt.Sprintf(`application/rim+cbor; profile=%q`, profile)) + schemeHandler, err := o.SchemePluginManager.LookupByMediaType( + fmt.Sprintf(`application/rim+cbor; profile=%q`, profile)) if err != nil { return nil, err } - scheme := endorsementHandler.GetAttestationScheme() + scheme := schemeHandler.GetAttestationScheme() + label := fmt.Sprintf("%s/%s", DummyTenantID, scheme) - storeHandler, err := o.StorePluginManager.LookupByAttestationScheme(scheme) + authority, err := comid.NewCryptoKeyTaggedBytes([]byte("dummyauth")) if err != nil { return nil, err } - queryKeys, err := storeHandler.SynthCoservQueryKeys(DummyTenantID, query.Query) + environments, err := querySelectorToEnvironments(&query.Query.EnvironmentSelector) if err != nil { return nil, err } - var resultSet []string - for _, key := range queryKeys { - res, err := store.Get(key) - if err != nil && !errors.Is(err, kvstore.ErrKeyNotFound) { - return nil, fmt.Errorf("lookup %q in %s failed: %w", key, storeName, err) + resultSet := coserv.NewResultSet() + + // add (dummy, for now -- TODO) expiry + dummyExpiry := time.Now().Add(time.Hour * 1) + resultSet.SetExpiry(dummyExpiry) + + switch query.Query.ArtifactType { + case coserv.ArtifactTypeTrustAnchors: + keyTriples, err := o.getKeyTriples(environments, label, false) + if err != nil && !errors.Is(err, corimstore.ErrNoMatch) { + return nil, err + } + + for _, keyTriple := range keyTriples { + resultSet.AddAttestationKeys(coserv.AKQuad{ + Authorities: comid.NewCryptoKeys().Add(authority), + AKTriple: keyTriple, + }) + } + case coserv.ArtifactTypeReferenceValues: + valueTriples, err := o.getValueTriples(environments, label, false) + if err != nil && !errors.Is(err, corimstore.ErrNoMatch) { + return nil, err } - resultSet = append(resultSet, res...) + for _, valueTriple := range valueTriples { + resultSet.AddReferenceValues(coserv.RefValQuad{ + Authorities: comid.NewCryptoKeys().Add(authority), + RVTriple: valueTriple, + }) + } + default: + return nil, errors.New("only reference value and trust anchors are supported at present") } - coservResults, err := endorsementHandler.CoservRepackage(query.Query, resultSet) - if err != nil { - return nil, err + if err := query.AddResults(*resultSet); err != nil { + return nil, fmt.Errorf("could not add result set to query: %w", err) } - return coservResults, nil + return query.ToCBOR() } -func (o *GRPC) getEndorsementsFromProxy(handlerPlugin handler.ICoservProxyHandler, query *proto.EndorsementQueryIn) ([]byte, error) { +func (o *GRPC) getEndorsementsFromProxy( + handlerPlugin handlermod.ICoservProxyHandler, + query *proto.EndorsementQueryIn, +) ([]byte, error) { return handlerPlugin.GetEndorsements(DummyTenantID, query.Query) } -func (o *GRPC) GetEndorsements(ctx context.Context, query *proto.EndorsementQueryIn) (*proto.EndorsementQueryOut, error) { +func (o *GRPC) GetEndorsements( + ctx context.Context, + query *proto.EndorsementQueryIn, +) (*proto.EndorsementQueryOut, error) { o.logger.Debugw("GetEndorsements", "media-type", query.MediaType) var ( err error out []byte - handlerPlugin handler.ICoservProxyHandler + handlerPlugin handlermod.ICoservProxyHandler ) // First, check to see if we have a CoSERV proxy plugin that can handle this query @@ -772,14 +779,22 @@ func (o *GRPC) GetEndorsements(ctx context.Context, query *proto.EndorsementQuer }, nil } +// finalize prepares the final appraisal context to be returned to the client. +// The EAR is signed using the verifier private key. +// +// The error parameter indicates whether there was an error during the +// attestation process. If a non-nil error is supplied, it is classified as a +// verifier malfunction - unless it's of type "bad evidence", in which case it +// is logged and the error is cleared because we assume the relevant claim has +// been already set in the attestation result. func (o *GRPC) finalize( - appraisal *appraisal.Appraisal, + appraisal *appraisal.Context, err error, ) (*proto.AppraisalContext, error) { var signErr error if err != nil { - if errors.Is(err, handler.BadEvidenceError{}) { + if errors.Is(err, handlermod.BadEvidenceError{}) { // NOTE(setrofim): I debated whether this should be // logged as Info or Warn. Ultimately deciding to go // with Warn, to make it easier to identifier the @@ -814,7 +829,12 @@ func (o *GRPC) finalize( err = signErr } - return appraisal.GetContext(), err + pbAppraisal, pbErr := appraisal.ToProtobuf() + if pbErr != nil { + err = pbErr + } + + return pbAppraisal, err } func LoadTLSCreds( @@ -861,9 +881,16 @@ func LoadTLSCreds( return credentials.NewTLS(config), nil } -// LoadCaCerts loads and validates CA certificates from file paths -func LoadCACerts(paths []string) ([][]byte, error) { - certsPEM := [][]byte{} +// LoadCaCerts loads and validates CA certificates from file paths, as well as the system certs. +func LoadCACerts(paths []string) (*x509.CertPool, error) { + certPool, err := x509.SystemCertPool() + if err != nil { + return nil, fmt.Errorf("could not load system certs: %w", err) + } + + if len(paths) == 0 { + return certPool, nil + } for _, path := range paths { certPEM, err := os.ReadFile(path) @@ -871,15 +898,12 @@ func LoadCACerts(paths []string) ([][]byte, error) { return nil, fmt.Errorf("error reading cert in %s: %w", path, err) } - tempPool := x509.NewCertPool() - if !tempPool.AppendCertsFromPEM(certPEM) { + if !certPool.AppendCertsFromPEM(certPEM) { return nil, fmt.Errorf("invalid cert in %s", path) } - - certsPEM = append(certsPEM, certPEM) } - return certsPEM, nil + return certPool, nil } // SerializeCertPEMBytes converts the CA certificate pool to PEM format for transmission @@ -897,3 +921,45 @@ func SerializeCertPEMBytes(certPEMs [][]byte) ([]byte, error) { return allPEM.Bytes(), nil } + +func querySelectorToEnvironments(selector *coserv.EnvironmentSelector) ([]*comid.Environment, error) { + var ret []*comid.Environment + + if selector.Classes != nil { + for _, statefulClass := range *selector.Classes { + if statefulClass.Measurements != nil { + return nil, ErrMeasurementsNotSupported + } + + ret = append(ret, &comid.Environment{ + Class: statefulClass.Class, + }) + } + } + + if selector.Instances != nil { + for _, statefulInstance := range *selector.Instances { + if statefulInstance.Measurements != nil { + return nil, ErrMeasurementsNotSupported + } + + ret = append(ret, &comid.Environment{ + Instance: statefulInstance.Instance, + }) + } + } + + if selector.Groups != nil { + for _, statefulGroup := range *selector.Groups { + if statefulGroup.Measurements != nil { + return nil, ErrMeasurementsNotSupported + } + + ret = append(ret, &comid.Environment{ + Group: statefulGroup.Group, + }) + } + } + + return ret, nil +}