diff --git a/.gitignore b/.gitignore index c405ae26..af3e0cec 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ __generated__ __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 9a544119..a50dab54 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +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. -export COMBINED_PLUGINS = 1 - SHELL = /bin/bash SUBDIR += builtin @@ -55,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 55b2e8d3..ddd383b3 100644 Binary files a/end-to-end/input/cca-endorsements.cbor and b/end-to-end/input/cca-endorsements.cbor differ diff --git a/end-to-end/input/cca-evidence.cbor b/end-to-end/input/cca-evidence.cbor index 9fd5679f..048c6525 100644 Binary files a/end-to-end/input/cca-evidence.cbor and b/end-to-end/input/cca-evidence.cbor differ diff --git a/end-to-end/input/cca-realm-endorsements.cbor b/end-to-end/input/cca-realm-endorsements.cbor index 27672320..6938cb14 100644 Binary files a/end-to-end/input/cca-realm-endorsements.cbor and b/end-to-end/input/cca-realm-endorsements.cbor differ diff --git a/end-to-end/input/psa-endorsements.cbor b/end-to-end/input/psa-endorsements.cbor index db5fe6c7..8391de08 100644 Binary files a/end-to-end/input/psa-endorsements.cbor and b/end-to-end/input/psa-endorsements.cbor differ diff --git a/end-to-end/input/psa-evidence.cbor b/end-to-end/input/psa-evidence.cbor index bbe73869..6a0da012 100644 Binary files a/end-to-end/input/psa-evidence.cbor and b/end-to-end/input/psa-evidence.cbor differ diff --git a/end-to-end/input/src/cca-evidence.json b/end-to-end/input/src/cca-evidence.json index a408c74e..ca85d6ca 100644 --- a/end-to-end/input/src/cca-evidence.json +++ b/end-to-end/input/src/cca-evidence.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", @@ -46,6 +47,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/src/comid-cca-realm-refval.json b/end-to-end/input/src/comid-cca-realm-refval.json index 7cd2bfa2..ef5f0947 100644 --- a/end-to-end/input/src/comid-cca-realm-refval.json +++ b/end-to-end/input/src/comid-cca-realm-refval.json @@ -19,13 +19,6 @@ "reference-values": [ { "environment": { - "class": { - "id": { - "type": "uuid", - "value": "CD1F0E55-26F9-460D-B9D8-F7FDE171787C" - }, - "vendor": "Workload Client Ltd" - }, "instance": { "type": "bytes", "value": "Q0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQw==" @@ -76,4 +69,4 @@ } ] } - } \ No newline at end of file + } diff --git a/end-to-end/input/src/corim-cca-realm.json b/end-to-end/input/src/corim-cca-realm.json index 05b7acb8..13db7d40 100644 --- a/end-to-end/input/src/corim-cca-realm.json +++ b/end-to-end/input/src/corim-cca-realm.json @@ -1,17 +1,17 @@ { - "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" - ] - } - ] - } + "corim-id": "00000000-0000-0001-cca4-000000000001", + "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/end-to-end/input/src/corim-cca.json b/end-to-end/input/src/corim-cca.json index cbebc13b..b0461477 100644 --- a/end-to-end/input/src/corim-cca.json +++ b/end-to-end/input/src/corim-cca.json @@ -1,5 +1,5 @@ { - "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", + "corim-id": "00000000-0000-0001-cca6-000000000001", "dependent-rims": [ { "href": "https://parent.example/rims/ccb3aa85-61b4-40f1-848e-02ad6e8a254b", diff --git a/end-to-end/input/src/corim-psa.json b/end-to-end/input/src/corim-psa.json index f9528480..a7c23279 100644 --- a/end-to-end/input/src/corim-psa.json +++ b/end-to-end/input/src/corim-psa.json @@ -1,4 +1,4 @@ { - "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", + "corim-id": "00000000-0000-0001-p5a1-000000000001", "profile": "http://arm.com/psa/iot/1" } diff --git a/go.mod b/go.mod index 4666a56e..5e5a3b38 100644 --- a/go.mod +++ b/go.mod @@ -11,39 +11,43 @@ require ( github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.1 github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 github.com/denisbrodbeck/machineid v1.0.1 - github.com/fatih/color v1.14.1 + github.com/fatih/color v1.18.0 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-sql-driver/mysql v1.8.1 + github.com/go-sql-driver/mysql v1.9.3 github.com/golang/mock v1.6.0 + github.com/google/go-sev-guest v0.14.2-0.20251119154202-af1c107a648f github.com/google/go-tpm v0.3.3 github.com/google/uuid v1.6.0 github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-plugin v1.4.4 - github.com/jackc/pgx/v5 v5.6.0 + github.com/jackc/pgx/v5 v5.7.6 github.com/jellydator/ttlcache/v3 v3.0.0 - github.com/json-iterator/go v1.1.12 // indirect + github.com/jraman567/go-gen-ref v1.2.3 github.com/lestrrat-go/jwx/v2 v2.1.3 - github.com/mattn/go-sqlite3 v1.14.14 + github.com/lestrrat-go/jwx/v3 v3.0.8 + github.com/mattn/go-sqlite3 v1.14.28 github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/protoc-gen-go-json v1.1.0 github.com/moogar0880/problems v0.1.1 github.com/open-policy-agent/opa v0.68.0 github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 - github.com/spf13/afero v1.12.0 + github.com/spf13/afero v1.15.0 github.com/spf13/jwalterweatherman v1.1.0 - github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.19.0 - github.com/stretchr/testify v1.10.0 + github.com/spf13/pflag v1.0.10 + github.com/spf13/viper v1.21.0 + github.com/stretchr/testify v1.11.1 github.com/tbaehler/gin-keycloak v1.6.1 github.com/veraison/ccatoken v1.3.2-0.20250512122414-b26aba0635c4 github.com/veraison/cmw v0.2.0 - github.com/veraison/corim v1.1.3-0.20251002172919-3c18c66c77b0 + github.com/veraison/corim v1.1.3-0.20260214081209-effcd0f48c8a + github.com/veraison/corim-store v0.0.0-20260220100808-e966b3eab910 github.com/veraison/dice v0.0.1 - github.com/veraison/ear v1.1.2 + github.com/veraison/ear v1.1.4-0.20260213122616-3034258cda59 github.com/veraison/eat v0.0.0-20220117140849-ddaf59d69f53 github.com/veraison/parsec v0.2.1-0.20240912163334-0368b9c16228 github.com/veraison/psatoken v1.2.1-0.20240912124429-aec3ece7886e + github.com/veraison/ratsd v0.0.0-20260122210857-1ac35b2e2184 go.uber.org/zap v1.27.0 golang.org/x/text v0.31.0 google.golang.org/grpc v1.67.3 @@ -54,6 +58,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect + fortio.org/safecast v1.0.0 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.62 // indirect @@ -73,8 +78,9 @@ require ( github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.8.0 github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -84,54 +90,73 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.19.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.4 // indirect github.com/golang/glog v1.2.4 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/logger v1.1.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.3 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lestrrat-go/blackmagic v1.0.2 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect + github.com/lestrrat-go/httprc/v3 v3.0.0 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect - github.com/magiconair/properties v1.8.9 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/lestrrat-go/option/v2 v2.0.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/oklog/run v1.0.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/cast v1.7.1 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/cobra v1.10.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/uptrace/bun v1.2.16 // indirect + github.com/uptrace/bun/dialect/mysqldialect v1.2.16 // indirect + github.com/uptrace/bun/dialect/pgdialect v1.2.16 // indirect + github.com/uptrace/bun/dialect/sqlitedialect v1.2.16 // indirect + github.com/uptrace/bun/driver/sqliteshim v1.2.15 // indirect + github.com/uptrace/bun/extra/bundebug v1.2.15 // indirect + github.com/valyala/fastjson v1.6.4 // indirect github.com/veraison/go-cose v1.3.0 - github.com/veraison/swid v1.1.1-0.20230911094910-8ffdd07a22ca + github.com/veraison/swid v1.1.1-0.20251003121634-fd1f7f1e1897 + github.com/virtee/sev-snp-measure-go v0.0.0-20241128091219-920346c42ecb // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -141,30 +166,21 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.7.0 // indirect golang.org/x/crypto v0.45.0 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect + golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect + golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.66.3 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.38.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) - -require ( - github.com/google/go-sev-guest v0.14.2-0.20251119154202-af1c107a648f - github.com/jraman567/go-gen-ref v1.2.3 - github.com/veraison/ratsd v0.0.0-20251002182229-94bebd610d15 -) - -require ( - fortio.org/safecast v1.0.0 // indirect - github.com/google/logger v1.1.1 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/virtee/sev-snp-measure-go v0.0.0-20241128091219-920346c42ecb // indirect -) diff --git a/go.sum b/go.sum index 80b4713e..07bb1f14 100644 --- a/go.sum +++ b/go.sum @@ -714,14 +714,14 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= @@ -733,8 +733,9 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -751,8 +752,8 @@ github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -764,8 +765,8 @@ github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.3.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= @@ -809,9 +810,11 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -889,8 +892,6 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-configfs-tsm v0.3.2 h1:ZYmHkdQavfsvVGDtX7RRda0gamelUNUhu0A9fbiuLmE= -github.com/google/go-configfs-tsm v0.3.2/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo= github.com/google/go-sev-guest v0.14.2-0.20251119154202-af1c107a648f h1:UVLafZ3h85JE5e0QU5dUixIJa2PO5G51THLMuXrtnTw= github.com/google/go-sev-guest v0.14.2-0.20251119154202-af1c107a648f/go.mod h1:SK9vW+uyfuzYdVN0m8BShL3OQCtXZe/JPF7ZkpD3760= github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI= @@ -922,6 +923,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= @@ -969,7 +972,6 @@ github.com/hashicorp/go-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7 github.com/hashicorp/go-plugin v1.4.4/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -983,16 +985,18 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= -github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= +github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jellydator/ttlcache/v3 v3.0.0 h1:zmFhqrB/4sKiEiJHhtseJsNRE32IMVmJSs4++4gaQO4= github.com/jellydator/ttlcache/v3 v3.0.0/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jraman567/go-gen-ref v1.2.3 h1:NiPqwWea1eoG6Zn6kSQONdO2F3yrUZX7cmSFZEc0++I= github.com/jraman567/go-gen-ref v1.2.3/go.mod h1:3uZ9S9s0dPTcq+xdwNVxWrPNuvRepQZW5Xep4cXIB3s= @@ -1034,36 +1038,41 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= -github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= +github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k= github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= +github.com/lestrrat-go/httprc/v3 v3.0.0 h1:nZUx/zFg5uc2rhlu1L1DidGr5Sj02JbXvGSpnY4LMrc= +github.com/lestrrat-go/httprc/v3 v3.0.0/go.mod h1:k2U1QIiyVqAKtkffbg+cUmsyiPGQsb9aAfNQiNFuQ9Q= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= github.com/lestrrat-go/jwx/v2 v2.1.3 h1:Ud4lb2QuxRClYAmRleF50KrbKIoM1TddXgBrneT5/Jo= github.com/lestrrat-go/jwx/v2 v2.1.3/go.mod h1:q6uFgbgZfEmQrfJfrCo90QcQOcXFMfbI/fO0NqRtvZo= +github.com/lestrrat-go/jwx/v3 v3.0.8 h1:lOCHy+k4/mgRI8FkgkHO+NsUx1GXHHktGx0CIkFToyI= +github.com/lestrrat-go/jwx/v3 v3.0.8/go.mod h1:0P9rjqNMDOspNSetpKX86Go54jLSEwCh8ax4jQRGYL0= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= +github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= @@ -1087,6 +1096,8 @@ github.com/moogar0880/problems v0.1.1/go.mod h1:5Dxrk2sD7BfBAgnOzQ1yaTiuCYdGPUh4 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -1097,8 +1108,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 h1:lL+y4Xv20pVlCGyLzNHRC0I0rIHhIL1lTvHizoS/dU8= github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= @@ -1135,9 +1146,13 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= +github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1150,10 +1165,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -1161,32 +1174,33 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -1206,8 +1220,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tbaehler/gin-keycloak v1.6.1 h1:LOXSW5P4j6eGt667/IiKQiyHSBVsECKgvMqdoHtnijA= @@ -1215,22 +1229,40 @@ github.com/tbaehler/gin-keycloak v1.6.1/go.mod h1:BwUAwDQjym9NfSg6MfCIMjQoyG6WKO github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/uptrace/bun v1.2.16 h1:QlObi6ZIK5Ao7kAALnh91HWYNZUBbVwye52fmlQM9kc= +github.com/uptrace/bun v1.2.16/go.mod h1:jMoNg2n56ckaawi/O/J92BHaECmrz6IRjuMWqlMaMTM= +github.com/uptrace/bun/dialect/mysqldialect v1.2.16 h1:ok06dAS094cEKvKg38SVAnXMroNHNaM5ZtpRkPE/Oz0= +github.com/uptrace/bun/dialect/mysqldialect v1.2.16/go.mod h1:fjbFYeJZCK8z0m0ACvdgs+dbFdDIaLYWDr+jvaPLedQ= +github.com/uptrace/bun/dialect/pgdialect v1.2.16 h1:KFNZ0LxAyczKNfK/IJWMyaleO6eI9/Z5tUv3DE1NVL4= +github.com/uptrace/bun/dialect/pgdialect v1.2.16/go.mod h1:IJdMeV4sLfh0LDUZl7TIxLI0LipF1vwTK3hBC7p5qLo= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.16 h1:6wVAiYLj1pMibRthGwy4wDLa3D5AQo32Y8rvwPd8CQ0= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.16/go.mod h1:Z7+5qK8CGZkDQiPMu+LSdVuDuR1I5jcwtkB1Pi3F82E= +github.com/uptrace/bun/driver/sqliteshim v1.2.15 h1:M/rZJSjOPV4OmfTVnDPtL+wJmdMTqDUn8cuk5ycfABA= +github.com/uptrace/bun/driver/sqliteshim v1.2.15/go.mod h1:YqwxFyvM992XOCpGJtXyKPkgkb+aZpIIMzGbpaw1hIk= +github.com/uptrace/bun/extra/bundebug v1.2.15 h1:IY2Z/pVyVg0ApWnQ/pEnwe6BWxlDDATCz7IFZghutCs= +github.com/uptrace/bun/extra/bundebug v1.2.15/go.mod h1:JuE+BT7NjTZ9UKr74eC8s9yZ9dnQCeufDwFRTC8w3Xo= +github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= +github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/veraison/ccatoken v1.3.2-0.20250512122414-b26aba0635c4 h1:t2GQueIc1SrErZpprs2ll9ETaXln/nOCPVRq7OejzfQ= github.com/veraison/ccatoken v1.3.2-0.20250512122414-b26aba0635c4/go.mod h1:vMqdbW4H/8A3oT+24qssuIK3Aefy06XqzTELGg+gWAg= github.com/veraison/cmw v0.2.0 h1:BWEvwZnD4nn5osq6XwQpTRcGxwV+Su4t6ytdAbVXAJY= github.com/veraison/cmw v0.2.0/go.mod h1:OiYKk1t6/Fmmg30ZpSMzi4nKr5kt3374sNTkgxC5BDs= -github.com/veraison/corim v1.1.3-0.20251002172919-3c18c66c77b0 h1:rl3ANdIHIStRQEYVhU0BaNc87j0W38iWqTwu0HYcuMA= -github.com/veraison/corim v1.1.3-0.20251002172919-3c18c66c77b0/go.mod h1:NDUWXTTPOnpwTa79HULq+o/6dkgK6XymHdSRGP9YP8M= +github.com/veraison/corim v1.1.3-0.20260214081209-effcd0f48c8a h1:Y19AyrbBpuyQZ/Sa/Hyh6bo5FrO6FMeR6g3jjnjLMBE= +github.com/veraison/corim v1.1.3-0.20260214081209-effcd0f48c8a/go.mod h1:96PQ0lk+O9bzutKTDz66G2DaARYUp1BeR06EYwEwSH0= +github.com/veraison/corim-store v0.0.0-20260220100808-e966b3eab910 h1:hg09D27B9qkrN6zFQEs6wEG0qiTk451ExGMnSAq2tXY= +github.com/veraison/corim-store v0.0.0-20260220100808-e966b3eab910/go.mod h1:/SqPJwSHexrxsNtiAJ/JqNgvC6+yihOyRlrTJO+0GnY= github.com/veraison/dice v0.0.1 h1:dOm7ByDN/r4WlDsGkEUXzdPMXgTvAPTAksQ8+BwBrD4= github.com/veraison/dice v0.0.1/go.mod h1:QPMLc5LVMj08VZ+HNMYk4XxWoVYGAUBVm8Rd5V1hzxs= -github.com/veraison/ear v1.1.2 h1:Xs41FqAG8IyJaceqNFcX2+nf51Et1uyhmCJV8SZqw/8= -github.com/veraison/ear v1.1.2/go.mod h1:O3yKgZR04DWKHHiNxfXCMX9ky0cLVoC67TFks6JwEhI= +github.com/veraison/ear v1.1.4-0.20260213122616-3034258cda59 h1:tynt7VXUc7uVAsN3RyWySaAJZpdQv0Eyru+7Wgwi72s= +github.com/veraison/ear v1.1.4-0.20260213122616-3034258cda59/go.mod h1:1TYMa6pOtEMiLDYTjRBJNUYsVff2MKQsH2BRmUSxKG0= github.com/veraison/eat v0.0.0-20220117140849-ddaf59d69f53 h1:5gnX2TrGd/Xz8DOp2OaLtg/jLoIubSUTrgz6iZ58pJ4= github.com/veraison/eat v0.0.0-20220117140849-ddaf59d69f53/go.mod h1:+kxt8iuFiVvKRs2VQ1Ho7bbAScXAB/kHFFuP5Biw19I= github.com/veraison/go-cose v1.3.0 h1:2/H5w8kdSpQJyVtIhx8gmwPJ2uSz1PkyWFx0idbd7rk= @@ -1239,12 +1271,16 @@ github.com/veraison/parsec v0.2.1-0.20240912163334-0368b9c16228 h1:oMCBfNZ8yxeMH github.com/veraison/parsec v0.2.1-0.20240912163334-0368b9c16228/go.mod h1:hobpAGxGmjCyluLHTNMdgJYficPXno4HZWKJSuUwZ7w= github.com/veraison/psatoken v1.2.1-0.20240912124429-aec3ece7886e h1:W1OWcrRvfN0EWyldcpFgwl9xdKBbZUlk5pnbLTcR8Ec= github.com/veraison/psatoken v1.2.1-0.20240912124429-aec3ece7886e/go.mod h1:bXUwdYAGcRoclxe73JmO8Z9ngV9KDHqW20afM9Q0FKo= -github.com/veraison/ratsd v0.0.0-20251002182229-94bebd610d15 h1:7oo/WsvzHgm54FtzMq5g4GzU2dZmEJUQ21wPrSarNxQ= -github.com/veraison/ratsd v0.0.0-20251002182229-94bebd610d15/go.mod h1:RFQMnjXCJVqc8V33F4BCAE76E0fjHS+4b+JkCAlUiJk= -github.com/veraison/swid v1.1.1-0.20230911094910-8ffdd07a22ca h1:osmCKwWO/xM68Kz+rIXio1DNzEY2NdJOpGpoy5r8NlE= -github.com/veraison/swid v1.1.1-0.20230911094910-8ffdd07a22ca/go.mod h1:d5jt76uMNbTfQ+f2qU4Lt8RvWOTsv6PFgstIM1QdMH0= +github.com/veraison/ratsd v0.0.0-20260122210857-1ac35b2e2184 h1:Ns1OqSfMxRjpg40iqwT/2P10JI0TNAJV+CtDdxOV/Lo= +github.com/veraison/ratsd v0.0.0-20260122210857-1ac35b2e2184/go.mod h1:M267xUihMjj6XF3f4AKgD0kQQAr11+Hr4sRvfKL+1OA= +github.com/veraison/swid v1.1.1-0.20251003121634-fd1f7f1e1897 h1:ze1ulqK70S7PRignyZzFDBJHNVEDyISk5FDv9Uh3UFw= +github.com/veraison/swid v1.1.1-0.20251003121634-fd1f7f1e1897/go.mod h1:d5jt76uMNbTfQ+f2qU4Lt8RvWOTsv6PFgstIM1QdMH0= github.com/virtee/sev-snp-measure-go v0.0.0-20241128091219-920346c42ecb h1:iBPEloogBk7uK2Ygtz1l6gJabikXs8ASZCmormbn2lM= github.com/virtee/sev-snp-measure-go v0.0.0-20241128091219-920346c42ecb/go.mod h1:dEkBe8JnxU5itNjZDEQINFd7f7l4DtjfqRuzPQcit4w= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= @@ -1274,8 +1310,8 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= @@ -1302,6 +1338,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= @@ -1340,8 +1378,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1384,8 +1422,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1917,14 +1955,14 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -2006,8 +2044,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2031,13 +2067,23 @@ lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM= +modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU= +modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM= +modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= @@ -2046,19 +2092,35 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI= +modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/handler/coservproxy_rpc.go b/handler/coservproxy_rpc.go index d36d150e..d9b01922 100644 --- a/handler/coservproxy_rpc.go +++ b/handler/coservproxy_rpc.go @@ -1,8 +1,9 @@ -// Copyright 2025 Contributors to the Veraison project. +// Copyright 2025-2026 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 package handler import ( + "encoding/json" "fmt" "net/rpc" @@ -37,9 +38,12 @@ func (s *CoservProxyRPCServer) GetAttestationScheme(args interface{}, resp *stri return nil } -func (s *CoservProxyRPCServer) GetSupportedMediaTypes(args interface{}, resp *[]string) error { - *resp = s.Impl.GetSupportedMediaTypes() - return nil +func (s *CoservProxyRPCServer) GetSupportedMediaTypes(args interface{}, resp *[]byte) error { + var err error + mts := s.Impl.GetSupportedMediaTypes() + + *resp, err = json.Marshal(mts) + return err } type GetEndorsementArgs struct { @@ -86,10 +90,10 @@ func (c *CoservProxyRPCClient) GetAttestationScheme() string { return resp } -func (c *CoservProxyRPCClient) GetSupportedMediaTypes() []string { +func (c *CoservProxyRPCClient) GetSupportedMediaTypes() map[string][]string { var ( - resp []string - unused interface{} + resp []byte + unused any ) err := c.client.Call("Plugin.GetSupportedMediaTypes", &unused, &resp) @@ -98,7 +102,12 @@ func (c *CoservProxyRPCClient) GetSupportedMediaTypes() []string { return nil } - return resp + var ret map[string][]string + if err := json.Unmarshal(resp, &ret); err != nil { + log.Error(err) + } + + return ret } func (c *CoservProxyRPCClient) GetEndorsements( diff --git a/handler/endorsement.go b/handler/endorsement.go deleted file mode 100644 index 10c7d9bf..00000000 --- a/handler/endorsement.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2024-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import "encoding/json" - -const ( - EndorsementType_UNSPECIFIED string = "unspecified" - EndorsementType_REFERENCE_VALUE string = "reference value" - EndorsementType_VERIFICATION_KEY string = "trust anchor" -) - -type Endorsement struct { - Scheme string `json:"scheme"` - Type string `json:"type"` - - SubType string `json:"subType"` - Attributes json.RawMessage `json:"attributes"` -} -type EndorsementHandlerResponse struct { - ReferenceValues []Endorsement - TrustAnchors []Endorsement - SignerInfo map[string]string -} diff --git a/handler/endorsement_rpc.go b/handler/endorsement_rpc.go deleted file mode 100644 index 7dee0ed7..00000000 --- a/handler/endorsement_rpc.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2022-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" -) - -/* - Server-side RPC adapter around the Decoder plugin implementation - (plugin-side) -*/ - -var EndorsementHandlerRPC = &plugin.RPCChannel[IEndorsementHandler]{ - GetClient: getEndorsementClient, - GetServer: geEndorsementtServer, -} - -func getEndorsementClient(c *rpc.Client) interface{} { - return &EndorsementRPCClient{client: c} -} - -func geEndorsementtServer(i IEndorsementHandler) interface{} { - return &EndorsementRPCServer{Impl: i} -} - -type EndorsementRPCServer struct { - Impl IEndorsementHandler -} - -func (s *EndorsementRPCServer) Init(params EndorsementHandlerParams, unused interface{}) error { - return s.Impl.Init(params) -} - -func (s EndorsementRPCServer) Close(unused0 interface{}, unused1 interface{}) error { - return s.Impl.Close() -} - -func (s *EndorsementRPCServer) GetName(args interface{}, resp *string) error { - *resp = s.Impl.GetName() - return nil -} - -func (s *EndorsementRPCServer) GetAttestationScheme(args interface{}, resp *string) error { - *resp = s.Impl.GetAttestationScheme() - return nil -} - -func (s *EndorsementRPCServer) GetSupportedMediaTypes(args interface{}, resp *[]string) error { - *resp = s.Impl.GetSupportedMediaTypes() - return nil -} - -func (s EndorsementRPCServer) Decode(args []byte, resp *[]byte) error { - var decodeArgs struct { - Data []byte - MediaType string - CACertPool []byte - } - - if err := json.Unmarshal(args, &decodeArgs); err != nil { - return fmt.Errorf("failed to unmarshal decode arguments: %w", err) - } - - j, err := s.Impl.Decode(decodeArgs.Data, decodeArgs.MediaType, decodeArgs.CACertPool) - if err != nil { - return fmt.Errorf("plugin %q returned error: %w", s.Impl.GetName(), err) - } - - *resp, err = json.Marshal(j) - if err != nil { - return fmt.Errorf("failed to marshal plugin response: %w", err) - } - - return nil -} - -type CoservRepackageArgs struct { - Query string - ResultSet []string -} - -func (s EndorsementRPCServer) CoservRepackage(args CoservRepackageArgs, resp *[]byte) (err error) { - *resp, err = s.Impl.CoservRepackage(args.Query, args.ResultSet) - - return err -} - -/* - RPC client - (plugin caller side) -*/ - -type EndorsementRPCClient struct { - client *rpc.Client -} - -func (c EndorsementRPCClient) Init(params EndorsementHandlerParams) error { - var unused interface{} - - return c.client.Call("Plugin.Init", params, &unused) -} - -func (c EndorsementRPCClient) Close() error { - var ( - unused0 interface{} - unused1 interface{} - ) - - return c.client.Call("Plugin.Close", unused0, unused1) -} - -func (c EndorsementRPCClient) 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 EndorsementRPCClient) 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 EndorsementRPCClient) 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 EndorsementRPCClient) Decode(data []byte, mediaType string, caCertPool []byte) (*EndorsementHandlerResponse, error) { - var ( - err error - resp EndorsementHandlerResponse - j []byte - ) - - decodeArgs := struct { - Data []byte - MediaType string - CACertPool []byte - }{ - Data: data, - MediaType: mediaType, - CACertPool: caCertPool, - } - - args, err := json.Marshal(decodeArgs) - if err != nil { - return nil, fmt.Errorf("failed marshaling RPC arguments: %w", err) - } - - err = c.client.Call("Plugin.Decode", args, &j) - if err != nil { - return nil, fmt.Errorf("RPC server returned error: %w", err) - } - - err = json.Unmarshal(j, &resp) - if err != nil { - return nil, fmt.Errorf("failed unmarshaling response from RPC server: %w", err) - } - - return &resp, nil -} - -func (c EndorsementRPCClient) CoservRepackage(query string, resultSet []string) (resp []byte, err error) { - args := CoservRepackageArgs{Query: query, ResultSet: resultSet} - - if err = c.client.Call("Plugin.CoservRepackage", args, &resp); err != nil { - return nil, fmt.Errorf("Plugin.CoservRepackage RPC call failed: %w", ParseError(err)) - } - - return resp, nil -} diff --git a/handler/evidence_rpc.go b/handler/evidence_rpc.go deleted file mode 100644 index 36f30f19..00000000 --- a/handler/evidence_rpc.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import ( - "encoding/json" - "fmt" - "net/rpc" - - "github.com/veraison/ear" - "github.com/veraison/services/log" - "github.com/veraison/services/plugin" - "github.com/veraison/services/proto" -) - -var EvidenceHandlerRPC = &plugin.RPCChannel[IEvidenceHandler]{ - GetClient: getClient, - GetServer: getServer, -} - -func getClient(c *rpc.Client) interface{} { - return &RPCClient{client: c} -} - -func getServer(i IEvidenceHandler) interface{} { - return &RPCServer{Impl: i} -} - -type RPCServer struct { - Impl IEvidenceHandler -} - -func (s *RPCServer) GetName(args interface{}, resp *string) error { - *resp = s.Impl.GetName() - return nil -} - -func (s *RPCServer) GetAttestationScheme(args interface{}, resp *string) error { - *resp = s.Impl.GetAttestationScheme() - return nil -} - -func (s *RPCServer) GetSupportedMediaTypes(args interface{}, resp *[]string) error { - *resp = s.Impl.GetSupportedMediaTypes() - return nil -} - -type ExtractClaimsArgs struct { - Token []byte - TrustAnchors []string -} - -func (s *RPCServer) ExtractClaims(args ExtractClaimsArgs, resp *[]byte) error { - var token proto.AttestationToken - - err := json.Unmarshal(args.Token, &token) - if err != nil { - return fmt.Errorf("unmarshaling token: %w", err) - } - - extracted, err := s.Impl.ExtractClaims(&token, args.TrustAnchors) - if err != nil { - return err - } - - *resp, err = json.Marshal(extracted) - - return err -} - -type ValidateEvidenceIntegrityArgs struct { - Token []byte - TrustAnchors []string - Endorsements []string -} - -func (s *RPCServer) ValidateEvidenceIntegrity(args ValidateEvidenceIntegrityArgs, resp *[]byte) error { - var token proto.AttestationToken - - err := json.Unmarshal(args.Token, &token) - if err != nil { - return fmt.Errorf("unmarshaling token: %w", err) - } - - err = s.Impl.ValidateEvidenceIntegrity(&token, args.TrustAnchors, args.Endorsements) - - return err -} - -type AppraiseEvidenceArgs struct { - Evidence []byte - Endorsements []string -} - -func (s *RPCServer) AppraiseEvidence(args AppraiseEvidenceArgs, resp *[]byte) error { - var ( - ec proto.EvidenceContext - err error - ) - - err = json.Unmarshal(args.Evidence, &ec) - if err != nil { - return fmt.Errorf("unmarshaling evidence: %w", err) - } - - attestation, err := s.Impl.AppraiseEvidence(&ec, args.Endorsements) - if err != nil { - return err - } - - *resp, err = json.Marshal(attestation) - - return err -} - -type RPCClient struct { - client *rpc.Client -} - -func (s *RPCClient) GetName() string { - var ( - resp string - unused interface{} - ) - - err := s.client.Call("Plugin.GetName", &unused, &resp) - if err != nil { - log.Errorf("Plugin.GetName RPC call failed: %v", err) // nolint - return "" - } - - return resp -} - -func (s *RPCClient) GetAttestationScheme() string { - var ( - resp string - unused interface{} - ) - - err := s.client.Call("Plugin.GetAttestationScheme", &unused, &resp) - if err != nil { - log.Errorf("Plugin.GetAttestationScheme RPC call failed: %v", err) // nolint - return "" - } - - return resp -} - -func (s *RPCClient) GetSupportedMediaTypes() []string { - var ( - err error - resp []string - unused interface{} - ) - - err = s.client.Call("Plugin.GetSupportedMediaTypes", &unused, &resp) - if err != nil { - log.Errorf("Plugin.GetSupportedMediaTypes RPC call failed: %v", err) - return nil - } - - return resp -} - -func (s *RPCClient) ExtractEvidence( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - var ( - err error - args ExtractClaimsArgs - resp []byte - extracted map[string]interface{} - ) - - args.Token, err = json.Marshal(token) - if err != nil { - return nil, fmt.Errorf("marshaling token: %w", err) - } - args.TrustAnchors = trustAnchors - - err = s.client.Call("Plugin.ExtractEvidence", args, &resp) - if err != nil { - err = ParseError(err) - return nil, fmt.Errorf("Plugin.ExtractEvidence RPC call failed: %w", err) // nolint - } - - err = json.Unmarshal(resp, &extracted) - if err != nil { - return nil, fmt.Errorf("unmarshaling extracted evidence: %w", err) - } - - return extracted, nil -} - -func (s *RPCClient) ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - endorsements []string, -) error { - var ( - err error - args ValidateEvidenceIntegrityArgs - resp []byte - ) - - args.Token, err = json.Marshal(token) - if err != nil { - return fmt.Errorf("marshaling token: %w", err) - } - args.TrustAnchors = trustAnchors - args.Endorsements = endorsements - - err = s.client.Call("Plugin.ValidateEvidenceIntegrity", args, &resp) - - return ParseError(err) -} - -func (s *RPCClient) AppraiseEvidence(ec *proto.EvidenceContext, endorsements []string) (*ear.AttestationResult, error) { - var ( - args AppraiseEvidenceArgs - result ear.AttestationResult - err error - resp []byte - ) - - args.Evidence, err = json.Marshal(ec) - if err != nil { - return nil, fmt.Errorf("marshaling evidence: %w", err) - } - - args.Endorsements = endorsements - - err = s.client.Call("Plugin.AppraiseEvidence", args, &resp) - if err != nil { - err = ParseError(err) - return nil, fmt.Errorf("Plugin.AppraiseEvidence RPC call failed: %w", err) // nolint - } - - err = json.Unmarshal(resp, &result) - - return &result, err -} - -func (s *RPCClient) ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, -) (map[string]interface{}, error) { - var ( - err error - args ExtractClaimsArgs - extractedClaims map[string]interface{} - ) - - args.Token, err = json.Marshal(token) - if err != nil { - return nil, fmt.Errorf("marshaling token: %w", err) - } - - args.TrustAnchors = trustAnchors - - var resp []byte - err = s.client.Call("Plugin.ExtractClaims", args, &resp) - if err != nil { - err = ParseError(err) - return nil, fmt.Errorf("Plugin.ExtractClaims RPC call failed: %w", err) // nolint - } - - err = json.Unmarshal(resp, &extractedClaims) - if err != nil { - return nil, fmt.Errorf("unmarshaling extracted claims: %w", err) - } - - return extractedClaims, nil -} diff --git a/handler/idecoder_manager.go b/handler/idecoder_manager.go deleted file mode 100644 index 534d5010..00000000 --- a/handler/idecoder_manager.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2022-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import "go.uber.org/zap" - -type IDecoderManager interface { - Init(dir string, logger *zap.SugaredLogger) error - Close() error - Dispatch(mediaType string, data []byte) (*EndorsementHandlerResponse, error) - IsSupportedMediaType(mediaType string) bool - GetSupportedMediaTypes() []string -} diff --git a/handler/iendorsementhandler.go b/handler/iendorsementhandler.go deleted file mode 100644 index a653d163..00000000 --- a/handler/iendorsementhandler.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import ( - "github.com/veraison/services/plugin" -) - -// EndorsementHandlerParams are passed to IEndorsementHandler.Init() They are -// implementation-specific. -type EndorsementHandlerParams map[string]interface{} - -// IEndorsementHandler defines the interface to functionality for working with -// attestation scheme specific endorsement provisioning tokens (typically, -// CoRIM's). -type IEndorsementHandler interface { - plugin.IPluggable - - // Init() initializes the handler. - Init(params EndorsementHandlerParams) error - - // Close the decoder, finalizing any state it may contain. - Close() error - - // Decode the endorsements from the provided []byte with specified media type. - Decode(data []byte, mediaType string, caCertPool []byte) (*EndorsementHandlerResponse, error) - - // CoservRepackage reformats the supplied result set, appends it to the - // supplied CoSERV query and returns the resulting CoSERV as a CBOR-encoded - // byte buffer. - CoservRepackage(coservQuery string, resultSet []string) ([]byte, error) -} diff --git a/handler/ievidencehandler.go b/handler/ievidencehandler.go deleted file mode 100644 index 84f3c7c4..00000000 --- a/handler/ievidencehandler.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2021-2024 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import ( - "github.com/veraison/ear" - "github.com/veraison/services/plugin" - "github.com/veraison/services/proto" -) - -// IEvidenceHandler defines the interface to functionality for working with -// attestation scheme specific evidence tokens. This includes validating token -// integrity, extracting and appraising claims. -type IEvidenceHandler interface { - plugin.IPluggable - - // ExtractClaims parses the attestation token and returns claims - // extracted therefrom. - ExtractClaims( - token *proto.AttestationToken, - trustAnchors []string, - ) (map[string]interface{}, error) - - // ValidateEvidenceIntegrity verifies the structural integrity and validity of the - // token. The exact checks performed are scheme-specific, but they - // would typically involve, at the least, verifying the token's - // signature using the provided trust anchors and endorsements. If the - // validation fails, an error detailing what went wrong is returned. - // Note: key material required to validate the token would typically be - // provisioned as a Trust Anchor. However, depending on the - // requirements of the Scheme, it maybe be provisioned as an - // Endorsement instead, or in addition to the Trust Anchor. E.g., - // if the validation is performed via an x.509 cert chain, the - // root cert may be provisioned as a Trust Anchor, while - // intermediate certs may be provisioned as Endorsements (at a - // different point in time, by a different actor). - // TODO(setrofim): no distinction is currently made between validation - // failing due to an internal error, and it failing due to bad input - // (i.e. signature not matching). - ValidateEvidenceIntegrity( - token *proto.AttestationToken, - trustAnchors []string, - endorsementsStrings []string, - ) error - - // AppraiseEvidence evaluates the specified EvidenceContext against - // the specified endorsements, and returns an AttestationResult. - AppraiseEvidence( - ec *proto.EvidenceContext, - endorsements []string, - ) (*ear.AttestationResult, error) -} diff --git a/handler/ischemehandler.go b/handler/ischemehandler.go new file mode 100644 index 00000000..cfc8154f --- /dev/null +++ b/handler/ischemehandler.go @@ -0,0 +1,59 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package handler + +import ( + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/services/plugin" + "github.com/veraison/services/vts/appraisal" +) + +// ISchemeHandler defines the full interface that needs to be implemented by an +// attestation scheme. This includes the common pluggable interface used for +// runtime discovery. +type ISchemeHandler interface { + plugin.IPluggable + ISchemeImplementation + + // GetSupportedProvisioningMediaTypes returns the list of media types + // supported on the provisioning path; i.e. the supported endorsement + // formats. + GetSupportedProvisioningMediaTypes() []string + + // GetSupportedVerificationMediaTypes returns the list of media types + // supported on the verification path; i.e. the supported attestation + // evidence formats. + GetSupportedVerificationMediaTypes() []string + + // ValidateCorim validates the contents of the provided CoRIM with respect + // to the specified profile. + ValidateCorim(uc *corim.UnsignedCorim) (*ValidateCorimResponse, error) + + // GetReferenceValueIDs returns a slice of Environments used to retrieve + // reference values for an attestation scheme, using the claims + // extracted from attestation token and the associated trust anchors. + GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, + ) ([]*comid.Environment, error) + + // ValidateEvidenceIntegrity verifies the structural integrity and validity of the + // token. The exact checks performed are scheme-specific, but they + // would typically involve, at the least, verifying the token's + // signature using the provided trust anchors and endorsements. If the + // validation fails, an error detailing what went wrong is returned. + // Note: key material required to validate the token would typically be + // provisioned as a Trust Anchor. However, depending on the + // requirements of the Scheme, it maybe be provisioned as an + // Endorsement instead, or in addition to the Trust Anchor. E.g., + // if the validation is performed via an x.509 cert chain, the + // root cert may be provisioned as a Trust Anchor, while + // intermediate certs may be provisioned as Endorsements (at a + // different point in time, by a different actor). + ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, + ) error +} diff --git a/handler/ischemeimplementation.go b/handler/ischemeimplementation.go new file mode 100644 index 00000000..0a36fbea --- /dev/null +++ b/handler/ischemeimplementation.go @@ -0,0 +1,38 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package handler + +import ( + "github.com/veraison/corim/comid" + "github.com/veraison/ear" + "github.com/veraison/services/vts/appraisal" +) + +// ISchemeImplementation is the subset of the ISchemeHandler interface that +// must be implemented by schemes that make use of SchemeHandlerWrapper. +type ISchemeImplementation interface { + // GetTrustAnchorIDs returns a slice of Environements used to + // retrieve the trust anchors associated with evidence. The trust + // anchors may be necessary to validate the entire evidence and/or extract + // its claims (if it is encrypted). + GetTrustAnchorIDs(evidence *appraisal.Evidence) ([]*comid.Environment, error) + + // ExtractClaims parses the attestation evidence and returns claims + // extracted therefrom. + ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + ) (map[string]any, error) + + // AppraiseClaims evaluates the specified claims against + // the specified endorsements, and returns an AttestationResult. + AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, + ) (*ear.AttestationResult, error) + + // Optionally, if ValidateComid is implemented, and ValidateCorim is not, + // then ValidateComid will be invoked for every CoMID inside provisioned + // each provisioned CoRIM. + // ValidateComid(c *comid.Comid) error +} diff --git a/handler/istorehandler.go b/handler/istorehandler.go deleted file mode 100644 index e2803f28..00000000 --- a/handler/istorehandler.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024-2025 Contributors to the Veraison project. -// SPDX-License-Identifier: Apache-2.0 -package handler - -import ( - "github.com/veraison/services/plugin" - "github.com/veraison/services/proto" -) - -// IStoreHandler defines the interfaces for creating and obtaining keys -// to access objects in the Veraison storage layer. -// This includes obtaining Trust Anchor IDs from evidence and synthesizing -// Reference Value and TrustAnchor keys from endorsements -type IStoreHandler interface { - plugin.IPluggable - - // GetTrustAnchorIDs returns a slice of trust anchor identifiers used to - // retrieve the trust anchors associated with this token. The trust anchors - // may be necessary to validate the entire token and/or extract its claims - // (if it is encrypted). - GetTrustAnchorIDs(token *proto.AttestationToken) ([]string, error) - - // GetRefValueIDs returns a slice of identifiers used to retrieve - // reference values for an attestation scheme, using the claims - // extracted from attestation token and the associated trust anchors. - GetRefValueIDs( - tenantID string, - trustAnchors []string, - claims map[string]interface{}, - ) ([]string, error) - - // SynthKeysFromRefValue synthesizes lookup key(s) for the - // provided reference value endorsement. - SynthKeysFromRefValue(tenantID string, refVal *Endorsement) ([]string, error) - - // SynthKeysFromTrustAnchor synthesizes lookup key(s) for the provided - // trust anchor. - SynthKeysFromTrustAnchor(tenantID string, ta *Endorsement) ([]string, error) - - // SynthCoservQueryKeys synthesizes lookup keys for the supplied CoSERV - // environment selector. - SynthCoservQueryKeys(tenantID string, query string) ([]string, error) -} diff --git a/handler/plugin.go b/handler/plugin.go index 56224423..c7ffc2a3 100644 --- a/handler/plugin.go +++ b/handler/plugin.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 handler @@ -6,30 +6,25 @@ import ( "github.com/veraison/services/plugin" ) -func RegisterEndorsementHandler(i IEndorsementHandler) { - err := plugin.RegisterImplementation("endorsement-handler", i, EndorsementHandlerRPC) +func RegisterCoservProxyHandler(i ICoservProxyHandler) { + err := plugin.RegisterImplementation("coserv-proxy-handler", i, CoservProxyHandlerRPC) if err != nil { panic(err) } } -func RegisterEvidenceHandler(i IEvidenceHandler) { - err := plugin.RegisterImplementation("evidence-handler", i, EvidenceHandlerRPC) +func RegisterSchemeHandler(i ISchemeHandler) { + err := plugin.RegisterImplementation("scheme-handler", i, SchemeHandlerRPC) if err != nil { panic(err) } } -func RegisterStoreHandler(i IStoreHandler) { - err := plugin.RegisterImplementation("store-handler", i, StoreHandlerRPC) +func RegisterSchemeImplementation(desc SchemeDescriptor, i ISchemeImplementation) { + wrapper, err := NewSchemeImplementationWrapper(desc, i) if err != nil { panic(err) } -} -func RegisterCoservProxyHandler(i ICoservProxyHandler) { - err := plugin.RegisterImplementation("coserv-proxy-handler", i, CoservProxyHandlerRPC) - if err != nil { - panic(err) - } + RegisterSchemeHandler(wrapper) } diff --git a/handler/scheme_rpc.go b/handler/scheme_rpc.go new file mode 100644 index 00000000..2f35f493 --- /dev/null +++ b/handler/scheme_rpc.go @@ -0,0 +1,427 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package handler + +import ( + "encoding/json" + "fmt" + "net/rpc" + "reflect" + + "github.com/fxamacker/cbor/v2" + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/ear" + "github.com/veraison/services/log" + "github.com/veraison/services/plugin" + "github.com/veraison/services/proto" + "github.com/veraison/services/vts/appraisal" + "go.uber.org/zap" +) + +var SchemeHandlerRPC = &plugin.RPCChannel[ISchemeHandler]{ + GetClient: getSchemeClient, + GetServer: getSchemeServer, +} + +func getSchemeClient(c *rpc.Client) any { + return &SchemeRPCClient{client: c, logger: log.Named("scheme-rpc")} +} + +func getSchemeServer(i ISchemeHandler) any { + return &SchemeRPCServer{Impl: i} +} + +type SchemeRPCClient struct { + client *rpc.Client + logger *zap.SugaredLogger +} + +func (o *SchemeRPCClient) GetName() string { + var ( + unused any + resp string + ) + + if err := o.client.Call("Plugin.GetName", &unused, &resp); err != nil { + return "" + } + + return resp +} + +func (o *SchemeRPCClient) GetAttestationScheme() string { + var ( + unused any + resp string + ) + + if err := o.client.Call("Plugin.GetAttestationScheme", &unused, &resp); err != nil { + return "" + } + + return resp +} + +func (o *SchemeRPCClient) GetSupportedMediaTypes() map[string][]string { + var ( + unused any + resp []byte + ) + + if err := o.client.Call("Plugin.GetSupportedMediaTypes", &unused, &resp); err != nil { + return nil + } + + var ret map[string][]string + if err := json.Unmarshal(resp, &ret); err != nil { + o.logger.Error(err) + } + + return ret +} + +func (o *SchemeRPCClient) GetSupportedProvisioningMediaTypes() []string { + var ( + unused any + resp []string + ) + + if err := o.client.Call("Plugin.GetSupportedProvisioningMediaTypes", &unused, &resp); err != nil { + return []string{} + } + + return resp +} + +func (o *SchemeRPCClient) GetSupportedVerificationMediaTypes() []string { + var ( + unused any + resp []string + ) + + if err := o.client.Call("Plugin.GetSupportedVerificationMediaTypes", &unused, &resp); err != nil { + return []string{} + } + + return resp +} + +func (o *SchemeRPCClient) ValidateCorim(uc *corim.UnsignedCorim) (*ValidateCorimResponse, error) { + toValidate, err := uc.ToCBOR() + if err != nil { + return nil, fmt.Errorf("mashalling CoRIM: %w", err) + } + + var rawResp []byte + if err = o.client.Call("Plugin.ValidateCorim", toValidate, &rawResp); err != nil { + return nil, ParseError(err) + } + + var resp ValidateCorimResponse + if err = json.Unmarshal(rawResp, &resp); err != nil { + return nil, err + } + + return &resp, nil +} + +func (o *SchemeRPCClient) GetReferenceValueIDs( + trustAnchors []*comid.KeyTriple, + claims map[string]any, +) ([]*comid.Environment, error) { + taCBOR, err := cbor.Marshal(trustAnchors) + if err != nil { + return nil, err + } + + claimsCBOR, err := cbor.Marshal(claims) + if err != nil { + return nil, err + } + + args := proto.GetReferenceValueIDsArgs{ + TrustAnchors: taCBOR, + Claims: claimsCBOR, + } + + var rawResp []byte + if err = o.client.Call("Plugin.GetReferenceValueIDs", &args, &rawResp); err != nil { + return nil, ParseError(err) + } + + var ret []*comid.Environment + if err := cbor.Unmarshal(rawResp, &ret); err != nil { + return nil, err + } + + return ret, nil +} + +func (o *SchemeRPCClient) ValidateEvidenceIntegrity( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, + endorsements []*comid.ValueTriple, +) error { + taCBOR, err := cbor.Marshal(trustAnchors) + if err != nil { + return err + } + + enCBOR, err := cbor.Marshal(endorsements) + if err != nil { + return err + } + + args := proto.ValidateEvidenceIntegrityArgs{ + Evidence: evidence.ToProtobuf(), + TrustAnchors: taCBOR, + Endorsements: enCBOR, + } + + var unused []byte + err = o.client.Call("Plugin.ValidateEvidenceIntegrity", &args, &unused) + return ParseError(err) +} + +func (o *SchemeRPCClient) GetTrustAnchorIDs( + evidence *appraisal.Evidence, +) ([]*comid.Environment, error) { + args := evidence.ToProtobuf() + + var rawResp []byte + if err := o.client.Call("Plugin.GetTrustAnchorIDs", &args, &rawResp); err != nil { + return nil, ParseError(err) + } + + var ret []*comid.Environment + if err := cbor.Unmarshal(rawResp, &ret); err != nil { + return nil, err + } + + return ret, nil +} + +func (o *SchemeRPCClient) ExtractClaims( + evidence *appraisal.Evidence, + trustAnchors []*comid.KeyTriple, +) (map[string]any, error) { + taCBOR, err := cbor.Marshal(trustAnchors) + if err != nil { + return nil, err + } + + args := proto.ExtractClaimsArgs{ + Evidence: evidence.ToProtobuf(), + TrustAnchors: taCBOR, + } + + var resp []byte + if err := o.client.Call("Plugin.ExtractClaims", &args, &resp); err != nil { + return nil, ParseError(err) + } + + var claims map[string]any + if err := claimsDecMode.Unmarshal(resp, &claims); err != nil { + return nil, err + } + + return claims, nil +} + +func (o *SchemeRPCClient) AppraiseClaims( + claims map[string]any, + endorsements []*comid.ValueTriple, +) (*ear.AttestationResult, error) { + claimsCBOR, err := cbor.Marshal(claims) + if err != nil { + return nil, err + } + + enCBOR, err := cbor.Marshal(endorsements) + if err != nil { + return nil, err + } + + args := proto.AppraiseClaimsArgs{ + Claims: claimsCBOR, + Endorsements: enCBOR, + } + + var rawResp []byte + if err := o.client.Call("Plugin.AppraiseClaims", &args, &rawResp); err != nil { + return nil, ParseError(err) + } + + var ret ear.AttestationResult + if err := json.Unmarshal(rawResp, &ret); err != nil { + return nil, err + } + + return &ret, nil +} + +type SchemeRPCServer struct { + Impl ISchemeHandler +} + +func (o *SchemeRPCServer) GetName(unused any, resp *string) error { + *resp = o.Impl.GetName() + return nil +} + +func (o *SchemeRPCServer) GetAttestationScheme(unused any, resp *string) error { + *resp = o.Impl.GetAttestationScheme() + return nil +} + +func (o *SchemeRPCServer) GetSupportedMediaTypes(unused any, resp *[]byte) error { + var err error + mts := o.Impl.GetSupportedMediaTypes() + + *resp, err = json.Marshal(mts) + return err +} + +func (o *SchemeRPCServer) GetSupportedProvisioningMediaTypes(unused any, resp *[]string) error { + *resp = o.Impl.GetSupportedProvisioningMediaTypes() + return nil +} + +func (o *SchemeRPCServer) GetSupportedVerificationMediaTypes(unused any, resp *[]string) error { + *resp = o.Impl.GetSupportedVerificationMediaTypes() + return nil +} + +func (o *SchemeRPCServer) ValidateCorim(toValidate []byte, resp *[]byte) error { + uc, err := corim.UnmarshalAndValidateUnsignedCorimFromCBOR(toValidate) + if err != nil { + *resp, err = json.Marshal(ValidateCorimResponse{ + IsValid: false, + Message: err.Error(), + }) + return err + } + + ret, err := o.Impl.ValidateCorim(uc) + if err != nil { + return err + } + + *resp, err = json.Marshal(ret) + return err +} + +func (o *SchemeRPCServer) GetReferenceValueIDs( + params *proto.GetReferenceValueIDsArgs, + resp *[]byte, +) error { + var trustAnchors []*comid.KeyTriple + if err := cbor.Unmarshal(params.TrustAnchors, &trustAnchors); err != nil { + return err + } + + var claims map[string]any + if err := claimsDecMode.Unmarshal(params.Claims, &claims); err != nil { + return err + } + + ret, err := o.Impl.GetReferenceValueIDs(trustAnchors, claims) + if err != nil { + return err + } + + *resp, err = cbor.Marshal(ret) + return err +} + +func (o *SchemeRPCServer) ValidateEvidenceIntegrity( + params *proto.ValidateEvidenceIntegrityArgs, + unused *[]byte, +) error { + evidence := appraisal.NewEvidenceFromProtobuf(params.Evidence) + + var trustAnchors []*comid.KeyTriple + if err := cbor.Unmarshal(params.TrustAnchors, &trustAnchors); err != nil { + return err + } + + var endorsements []*comid.ValueTriple + if err := cbor.Unmarshal(params.Endorsements, &endorsements); err != nil { + return err + } + + return o.Impl.ValidateEvidenceIntegrity(evidence, trustAnchors, endorsements) +} + +func (o *SchemeRPCServer) GetTrustAnchorIDs( + params *proto.AttestationToken, + resp *[]byte, +) error { + evidence := appraisal.NewEvidenceFromProtobuf(params) + + taIDs, err := o.Impl.GetTrustAnchorIDs(evidence) + if err != nil { + return err + } + + *resp, err = cbor.Marshal(taIDs) + return err +} + +func (o *SchemeRPCServer) ExtractClaims( + params *proto.ExtractClaimsArgs, + resp *[]byte, +) error { + evidence := appraisal.NewEvidenceFromProtobuf(params.Evidence) + + var trustAnchors []*comid.KeyTriple + if err := cbor.Unmarshal(params.TrustAnchors, &trustAnchors); err != nil { + return err + } + + claims, err := o.Impl.ExtractClaims(evidence, trustAnchors) + if err != nil { + return err + } + + *resp, err = cbor.Marshal(claims) + return err +} + +func (o *SchemeRPCServer) AppraiseClaims( + params *proto.AppraiseClaimsArgs, + resp *[]byte, +) error { + var endorsements []*comid.ValueTriple + if err := cbor.Unmarshal(params.Endorsements, &endorsements); err != nil { + return err + } + + var claims map[string]any + if err := claimsDecMode.Unmarshal(params.Claims, &claims); err != nil { + return err + } + + ret, err := o.Impl.AppraiseClaims(claims, endorsements) + if err != nil { + return err + } + + *resp, err = json.Marshal(ret) + return err +} + +var claimsDecMode cbor.DecMode + +func init() { + decOpts := cbor.DecOptions{ + DefaultMapType: reflect.TypeFor[map[string]any](), + } + + var err error + claimsDecMode, err = decOpts.DecMode() + if err != nil { + panic(err) + } +} diff --git a/handler/schemedescriptor.go b/handler/schemedescriptor.go new file mode 100644 index 00000000..2c5b1f15 --- /dev/null +++ b/handler/schemedescriptor.go @@ -0,0 +1,70 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package handler + +import ( + "errors" + "slices" + + "github.com/veraison/services/vts/appraisal" +) + +// SchemeVersion represents the versions information for the scheme +type SchemeVersion struct { + // Major version of the scheme. Changes to the major version indicate + // compatibility breaks (e.g. dropping of previously-supported input + // formats, changes to existing entries in the attestation result, etc). + Major int + // Minor version of the scheme. Changes to the minor version (without a + // major version change)indicate backward-compatible changes (e.g. + // support for new input formats, additions to the attestation result, + // purely internal changes, etc). + Minor int +} + +// SchemeDescriptor groups together descriptive information about an +// attestation scheme. +type SchemeDescriptor struct { + // The name of the attestation scheme. This is used to identify the + // scheme. It also forms a part of the policy ID in the attestation + // result. This must be unique. + Name string + // VersionMajor is the current major version of the scheme (see + // SchemeVersion above). + VersionMajor int + // VersionMinor is the current minor version of the scheme (see + // SchemeVersion above). + VersionMinor int + // CorimProfiles is a list of CoRIM profiles containing endorsements + // and trust anchors for this scheme. This must not overlap with any + // other registered scheme. + CorimProfiles []string + // EvidenceMediaTypes is the list of attesation evidence media types + // handled by this scheme. This must not overlap with any other + // registered scheme. + EvidenceMediaTypes []string +} + +func (o *SchemeDescriptor) Validate() error { + if o.Name == "" { + return errors.New("name not set") + } + + if len(o.CorimProfiles) == 0 { + return errors.New("CoRIM profiles not set") + } + + if len(o.EvidenceMediaTypes) == 0 { + return errors.New("evidence media types not set") + } + + return nil +} + +func (o *SchemeDescriptor) EvidenceIsSupported(ev *appraisal.Evidence) bool { + return slices.Contains(o.EvidenceMediaTypes, ev.MediaType) +} + +func (o *SchemeDescriptor) Version() SchemeVersion { + return SchemeVersion{Major: o.VersionMajor, Minor: o.VersionMinor} +} diff --git a/handler/schemeimplementationwrapper.go b/handler/schemeimplementationwrapper.go new file mode 100644 index 00000000..39dba093 --- /dev/null +++ b/handler/schemeimplementationwrapper.go @@ -0,0 +1,183 @@ +// Copyright 2026 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package handler + +import ( + "errors" + "fmt" + "strings" + + "github.com/veraison/corim/comid" + "github.com/veraison/corim/corim" + "github.com/veraison/ear" + "github.com/veraison/services/vts/appraisal" +) + +type SchemeImplementationWrapper struct { + Desc SchemeDescriptor + Impl ISchemeImplementation +} + +func NewSchemeImplementationWrapper( + desc SchemeDescriptor, + impl ISchemeImplementation, +) (*SchemeImplementationWrapper, error) { + if err := desc.Validate(); err != nil { + return nil, err + } + + return &SchemeImplementationWrapper{Desc: desc, Impl: impl}, nil +} + +func MustNewSchemeImplementationWrapper( + desc SchemeDescriptor, + impl ISchemeImplementation, +) *SchemeImplementationWrapper { + ret, err := NewSchemeImplementationWrapper(desc, impl) + if err != nil { + panic(err) + } + + return ret +} + +func (o *SchemeImplementationWrapper) GetName() string { + name := strings.ToLower(strings.ReplaceAll(o.Desc.Name, " ", "-")) + return fmt.Sprintf("%s-scheme-plugin", name) +} + +func (o *SchemeImplementationWrapper) GetAttestationScheme() string { + return o.Desc.Name +} + +func (o *SchemeImplementationWrapper) GetSupportedMediaTypes() map[string][]string { + return map[string][]string{ + "provisioning": o.GetSupportedProvisioningMediaTypes(), + "verification": o.GetSupportedVerificationMediaTypes(), + } +} + +func (o *SchemeImplementationWrapper) GetSupportedProvisioningMediaTypes() []string { + ret := make([]string, 0, len(o.Desc.CorimProfiles)*2) + + for _, profile := range o.Desc.CorimProfiles { + ret = append(ret, + fmt.Sprintf(`application/rim+cbor; profile="%s"`, profile), + fmt.Sprintf(`application/rim+cose; profile="%s"`, profile), + ) + } + + return ret +} + +func (o *SchemeImplementationWrapper) GetSupportedVerificationMediaTypes() []string { + return o.Desc.EvidenceMediaTypes +} + +func (o *SchemeImplementationWrapper) ValidateCorim(uc *corim.UnsignedCorim) (*ValidateCorimResponse, error) { + corimImpl, ok := o.Impl.(interface { + ValidateCorim(*corim.UnsignedCorim) (*ValidateCorimResponse, error) + }) + if ok { + return corimImpl.ValidateCorim(uc) + } + + comidImpl, ok := o.Impl.(interface { + ValidateComid(*comid.Comid) error + }) + if ok { + for i, tag := range uc.Tags { + if tag.Number == corim.ComidTag { + 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) + } + + err = comidImpl.ValidateComid(&c) + if err != nil { + return &ValidateCorimResponse{ + IsValid: true, + Message: fmt.Sprintf("CoMID at index %d: %s", i, err.Error()), + }, nil + } + } + } + + return &ValidateCorimResponse{IsValid: true, Message: ""}, 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 bb497ebe..6a32e7c3 100644 Binary files a/integration-tests/data/endorsements/corim-enacttrust-badta.cbor and b/integration-tests/data/endorsements/corim-enacttrust-badta.cbor differ diff --git a/integration-tests/data/endorsements/corim-enacttrust-mini.json b/integration-tests/data/endorsements/corim-enacttrust-mini.json index c73bcf4d..2dbfc17b 100644 --- a/integration-tests/data/endorsements/corim-enacttrust-mini.json +++ b/integration-tests/data/endorsements/corim-enacttrust-mini.json @@ -1,4 +1,4 @@ { "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc", - "profile": "http://enacttrust.com/veraison/1.0.0" + "profile": "https://enacttrust.com/veraison/1.0.0" } diff --git a/integration-tests/docker/Dockerfile b/integration-tests/docker/Dockerfile index 2b358bd4..f4380f34 100644 --- a/integration-tests/docker/Dockerfile +++ b/integration-tests/docker/Dockerfile @@ -45,7 +45,8 @@ RUN pip install --upgrade pip && \ python-jose==3.3.0 \ ipdb==0.13.11 -ADD gen-enacttrust-token evcli cocli run-tests /home/tavern/.local/bin/ +ADD gen-enacttrust-token evcli cocli corim-store run-tests /home/tavern/.local/bin/ +ADD corim-store-config.yaml /home/tavern/.config/corim-store.yaml ADD bashrc /home/tavern/.bashrc ENTRYPOINT ["/home/tavern/.local/bin/run-tests"] diff --git a/integration-tests/tests/common.yaml b/integration-tests/tests/common.yaml index 406a9fc8..94d480f8 100644 --- a/integration-tests/tests/common.yaml +++ b/integration-tests/tests/common.yaml @@ -17,9 +17,9 @@ variables: bad-nonce: Ppfdfe2JzZLOk= endorsements-content-types: - psa.p1: application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1" - cca._: application/corim-unsigned+cbor; profile="http://arm.com/cca/ssd/1" - enacttrust._: application/corim-unsigned+cbor; profile="http://enacttrust.com/veraison/1.0.0" + psa.p1: application/rim+cbor; profile="http://arm.com/psa/iot/1" + cca._: application/rim+cbor; profile="http://arm.com/cca/ssd/1" + enacttrust._: application/rim+cbor; profile="https://enacttrust.com/veraison/1.0.0" evidence-content-types: psa.p1: application/psa-attestation-token cca._: application/eat-collection; profile="http://arm.com/CCA-SSD/1.0.0" diff --git a/integration-tests/tests/test_enacttrust_badkey.tavern.yaml b/integration-tests/tests/test_enacttrust_badkey.tavern.yaml index fc8bf7fd..02517868 100644 --- a/integration-tests/tests/test_enacttrust_badkey.tavern.yaml +++ b/integration-tests/tests/test_enacttrust_badkey.tavern.yaml @@ -34,4 +34,4 @@ stages: status_code: 200 json: status: failed - failure-reason: 'submit endorsement returned error: submit endorsements failed: RPC server returned error: plugin "corim (TPM EnactTrust profile)" returned error: CBOR decoding failed: did not see unsigned CoRIM tag' + failure-reason: 'submit endorsement returned error: submit endorsements failed: did not see unsigned CoRIM tag' diff --git a/integration-tests/tests/test_end_to_end.tavern.yaml b/integration-tests/tests/test_end_to_end.tavern.yaml index 29060c56..53d0bbb0 100644 --- a/integration-tests/tests/test_end_to_end.tavern.yaml +++ b/integration-tests/tests/test_end_to_end.tavern.yaml @@ -23,12 +23,12 @@ marks: # Indicates which nonce configurations ought to be used. - nonce vals: - - [psa, p1, good, full, ec.p256, good, nonce32] - - [psa, p1, good, mini, ec.p256, good, nonce32] - - [psa, p1, missingclaims, mini, ec.p256, noident, nonce32] - - [psa, p1, good, mini, bad, badcrypto, nonce32] - - [psa, p1, badinstance, full, ec.p256, badinstance, nonce32] - - [psa, p1, badswcomp, full, ec.p256, badswcomp, nonce32] + #- [psa, p1, good, full, ec.p256, good, nonce32] + #- [psa, p1, good, mini, ec.p256, good, nonce32] + #- [psa, p1, missingclaims, mini, ec.p256, noident, nonce32] + #- [psa, p1, good, mini, bad, badcrypto, nonce32] + #- [psa, p1, badinstance, full, ec.p256, badinstance, nonce32] + #- [psa, p1, badswcomp, full, ec.p256, badswcomp, nonce32] - [enacttrust, _, good, mini, ec.p256.enacttrust, good, nonce32] includes: diff --git a/integration-tests/tests/test_provisioning_empty_body.tavern.yaml b/integration-tests/tests/test_provisioning_empty_body.tavern.yaml index 7a1eb879..0095efc4 100644 --- a/integration-tests/tests/test_provisioning_empty_body.tavern.yaml +++ b/integration-tests/tests/test_provisioning_empty_body.tavern.yaml @@ -9,7 +9,7 @@ stages: method: POST url: https://{provisioning-service}/endorsement-provisioning/v1/submit headers: - content-type: 'application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"' + content-type: 'application/rim+cbor; profile="http://arm.com/psa/iot/1"' authorization: '{authorization}' # set via hook response: status_code: 400 diff --git a/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml b/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml index 6a29666d..2275d036 100644 --- a/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml +++ b/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml @@ -9,7 +9,7 @@ stages: method: POST url: https://{provisioning-service}/endorsement-provisioning/v1/submit headers: - content-type: 'application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"' + content-type: 'application/rim+cbor; profile="http://arm.com/psa/iot/1"' response: status_code: 401 diff --git a/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml b/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml index 7ade3b33..6e01c1b4 100644 --- a/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml +++ b/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml @@ -25,7 +25,7 @@ stages: method: POST url: https://{provisioning-service}/endorsement-provisioning/v1/submit headers: - content-type: 'application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"' + content-type: 'application/rim+cbor; profile="http://arm.com/psa/iot/1"' authorization: '{authorization}' # set via hook file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor response: diff --git a/integration-tests/utils/checkers.py b/integration-tests/utils/checkers.py index dcf0c61a..3333f6ca 100644 --- a/integration-tests/utils/checkers.py +++ b/integration-tests/utils/checkers.py @@ -1,4 +1,4 @@ -# Copyright 2023-2024 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 import os import json @@ -57,6 +57,7 @@ def compare_to_expected_result(response, expected, verifier_key): assert decoded_claims["ear.veraison.policy-claims"] == \ expected_claims["ear.veraison.policy-claims"] + def check_policy(response, active, name, rules_file): policy = _extract_policy(response.json()) @@ -111,4 +112,4 @@ def _extract_submods(response, key_file): def _extract_policy(data): policy = data policy['ctime'] = datetime.fromisoformat(policy['ctime']) - return policy \ No newline at end of file + return policy diff --git a/integration-tests/utils/generators.py b/integration-tests/utils/generators.py index 83a2368a..7f2ab21a 100644 --- a/integration-tests/utils/generators.py +++ b/integration-tests/utils/generators.py @@ -1,9 +1,11 @@ -# Copyright 2023-2024 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 import ast import json import os import shutil +import tempfile +import uuid from util import update_json, run_command @@ -225,6 +227,8 @@ def generate_corim(corim_template, comid_templates, output_path): comid_files = [os.path.join(output_dir, '.'.join([os.path.splitext(name)[0], 'cbor'])) for name in map(os.path.basename, comid_templates)] + corim_template = substitute_random_corim_id(corim_template) + corim_create_cmd = ' '.join( [f'cocli corim create --output {output_path} --template={corim_template}'] + [f'--comid={cf}' for cf in comid_files] @@ -272,7 +276,23 @@ def generate_cca_evidence_token(claims_file, iak_file, rak_file, token_file): f"--iak={iak_file} --rak={rak_file} --token={token_file}" run_command(evcli_command, 'generate CCA token') + def generate_enacttrust_evidence_token(claims_file, key_file, token_file, badnode): bn_flag = '-bad-node' if badnode else '' gentoken_command = f"gen-enacttrust-token {bn_flag} -key {key_file} -out {token_file} {claims_file}" run_command(gentoken_command, 'generate EnactTrust token') + + +def substitute_random_corim_id(path): + with open(path, 'r') as fh: + data = json.load(fh) + + if 'corim-id' not in data: + raise ValueError(f'did not see corim-id in {path}') + + data['corim-id'] = str(uuid.uuid4()) + + with tempfile.NamedTemporaryFile(delete=False, mode='w') as tf: + json.dump(data, tf) + return tf.name + diff --git a/integration-tests/utils/hooks.py b/integration-tests/utils/hooks.py index 77579ea0..dbf9fd3a 100644 --- a/integration-tests/utils/hooks.py +++ b/integration-tests/utils/hooks.py @@ -1,4 +1,4 @@ -# Copyright 2023-2024 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 import os @@ -107,9 +107,9 @@ def _set_cca_content_types(test, variables): profile = test.test_vars['profile'] corim_type = test.test_vars.get('corim_type', 'unsigned') ev_content_types = test.common_vars['evidence-content-types'] - + variables['evidence-content-type'] = ev_content_types[f'{scheme}.{profile}'] - + # Set platform and realm content types if corim_type == 'signed': # Use signed content types @@ -117,5 +117,5 @@ def _set_cca_content_types(test, variables): variables['realm-en-content-type'] = 'application/rim+cose; profile="http://arm.com/cca/realm/1"' else: # Use unsigned content types - variables['platform-en-content-type'] = 'application/corim-unsigned+cbor; profile="http://arm.com/cca/ssd/1"' - variables['realm-en-content-type'] = 'application/corim-unsigned+cbor; profile="http://arm.com/cca/realm/1"' + variables['platform-en-content-type'] = 'application/rim+cbor; profile="http://arm.com/cca/ssd/1"' + variables['realm-en-content-type'] = 'application/rim+cbor; profile="http://arm.com/cca/realm/1"' diff --git a/integration-tests/utils/util.py b/integration-tests/utils/util.py index d195ea49..f90d4312 100644 --- a/integration-tests/utils/util.py +++ b/integration-tests/utils/util.py @@ -1,4 +1,4 @@ -# Copyright 2023-2024 Contributors to the Veraison project. +# Copyright 2023-2026 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 import json import os @@ -49,9 +49,11 @@ def run_command(command: str, action: str) -> 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/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) 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 00000000..ce04c1a3 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-no-class.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-instance.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-instance.cbor new file mode 100644 index 00000000..7fc38e1b Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-instance.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-mkey.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-mkey.cbor new file mode 100644 index 00000000..8eb00777 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-mkey.cbor differ 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 00000000..39356b91 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-digests.cbor differ 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 00000000..02fb97e2 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-mkey.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-raw-value.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-raw-value.cbor new file mode 100644 index 00000000..559a767d Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-refval-no-raw-value.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-cert.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-cert.cbor new file mode 100644 index 00000000..7fde69b3 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-cert.cbor differ 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 00000000..7f3df6bd Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-instance.cbor differ 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 00000000..ea2636df Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-bad-ta-no-instance.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-platform-valid.cbor b/scheme/arm-cca/test/corim/corim-cca-platform-valid.cbor new file mode 100644 index 00000000..a2b309e3 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-platform-valid.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-realm-bad-instance.cbor b/scheme/arm-cca/test/corim/corim-cca-realm-bad-instance.cbor new file mode 100644 index 00000000..60e04369 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-realm-bad-instance.cbor differ 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 00000000..e0ef1b84 Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-instance.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-integ-regs.cbor b/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-integ-regs.cbor new file mode 100644 index 00000000..45419eee Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-integ-regs.cbor differ 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 00000000..3964860a Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-realm-bad-no-raw-value.cbor differ diff --git a/scheme/arm-cca/test/corim/corim-cca-realm-valid.cbor b/scheme/arm-cca/test/corim/corim-cca-realm-valid.cbor new file mode 100644 index 00000000..5816dbbe Binary files /dev/null and b/scheme/arm-cca/test/corim/corim-cca-realm-valid.cbor differ 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 a9350438..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValFour.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValOne.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValOne.cbor deleted file mode 100644 index c04944ee..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaComidCcaRefValOne.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValFour.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValFour.cbor deleted file mode 100644 index 53fb95e3..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValFour.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValOne.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValOne.cbor deleted file mode 100644 index f3cb1d06..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaNoProfileComidCcaRefValOne.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealm.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealm.cbor deleted file mode 100644 index 88244eeb..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealm.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidClass.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidClass.cbor deleted file mode 100644 index 8a6ff73a..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidClass.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidInstance.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidInstance.cbor deleted file mode 100644 index ffa3d276..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmInvalidInstance.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor deleted file mode 100644 index 0e4c85cf..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoClass.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor b/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor deleted file mode 100644 index 4d84201f..00000000 Binary files a/scheme/arm-cca/test/corim/unsignedCorimCcaRealmComidCcaRealmNoInstance.cbor and /dev/null differ diff --git a/scheme/arm-cca/test/evidence/cca-good.cbor b/scheme/arm-cca/test/evidence/cca-good.cbor new file mode 100644 index 00000000..e8e8583c Binary files /dev/null and b/scheme/arm-cca/test/evidence/cca-good.cbor differ 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 c47dab85..00000000 Binary files a/scheme/arm-cca/test/evidence/cca-token.cbor and /dev/null differ 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 00000000..f8555f88 Binary files /dev/null and b/scheme/parsec-cca/test/corim/corim-parsec-cca-valid.cbor differ diff --git a/scheme/parsec-cca/test/corim/src/ComidParsecCcaMultRefVal.json b/scheme/parsec-cca/test/corim/src/ComidParsecCcaMultRefVal.json deleted file mode 100644 index 10c0fe13..00000000 --- a/scheme/parsec-cca/test/corim/src/ComidParsecCcaMultRefVal.json +++ /dev/null @@ -1,108 +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": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=" - }, - "vendor": "ACME", - "model": "RoadRunner" - } - }, - "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", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" - } - }, - "value": { - "digests": [ - "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" - ] - } - }, - { - "key": { - "type": "psa.refval-id", - "value": { - "label": "M2", - "version": "1.2.3", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" - } - }, - "value": { - "digests": [ - "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" - ] - } - }, - { - "key": { - "type": "psa.refval-id", - "value": { - "label": "M3", - "version": "1", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" - } - }, - "value": { - "digests": [ - "sha-256:BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=" - ] - } - }, - { - "key": { - "type": "cca.platform-config-id", - "value": "cfg v1.0.0" - }, - "value": { - "raw-value": { - "type": "bytes", - "value": "AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY" - } - } - } - ] - } - ] - } -} \ No newline at end of file diff --git a/scheme/parsec-cca/test/corim/src/comid-parsec-cca-refval.json b/scheme/parsec-cca/test/corim/src/comid-parsec-cca-refval.json new file mode 100644 index 00000000..7f6929ff --- /dev/null +++ b/scheme/parsec-cca/test/corim/src/comid-parsec-cca-refval.json @@ -0,0 +1,106 @@ +{ + "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": "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/psa-iot/test/corim/src/ComidPsaIakPubOne.json b/scheme/parsec-cca/test/corim/src/comid-parsec-cca-ta.json similarity index 53% rename from scheme/psa-iot/test/corim/src/ComidPsaIakPubOne.json rename to scheme/parsec-cca/test/corim/src/comid-parsec-cca-ta.json index 43f4ceeb..f1aab713 100644 --- a/scheme/psa-iot/test/corim/src/ComidPsaIakPubOne.json +++ b/scheme/parsec-cca/test/corim/src/comid-parsec-cca-ta.json @@ -1,13 +1,11 @@ { - "lang": "en-GB", "tag-identity": { - "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", - "version": 0 + "id": "EEE06F93-E982-4DBC-9585-620A816C2E59" }, "entities": [ { - "name": "ACME Ltd.", - "regid": "https://acme.example", + "name": "Parsec", + "regid": "https://github.com/parallaxsecond", "roles": [ "tagCreator", "creator", @@ -22,20 +20,18 @@ "class": { "id": { "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + } }, "instance": { "type": "ueid", - "value": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "value": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" } }, "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/parsec-cca/test/corim/src/corim-parsec-cca.json b/scheme/parsec-cca/test/corim/src/corim-parsec-cca.json new file mode 100644 index 00000000..a3834f05 --- /dev/null +++ b/scheme/parsec-cca/test/corim/src/corim-parsec-cca.json @@ -0,0 +1,4 @@ +{ + "corim-id": "00000000-0000-0000-6cca-000000000000", + "profile": "tag:github.com/parallaxsecond,2023-03-03:cca" +} diff --git a/scheme/parsec-cca/test/corim/src/corimParsecCca.json b/scheme/parsec-cca/test/corim/src/corimParsecCca.json deleted file mode 100644 index 9796f95a..00000000 --- a/scheme/parsec-cca/test/corim/src/corimParsecCca.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": "tag:github.com/parallaxsecond,2023-03-03:cca", - "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/parsec-cca/test/corim/src/corims.yaml b/scheme/parsec-cca/test/corim/src/corims.yaml new file mode 100644 index 00000000..f53c4a9a --- /dev/null +++ b/scheme/parsec-cca/test/corim/src/corims.yaml @@ -0,0 +1,7 @@ +corim: corim-parsec-cca +outdir: .. +workdir: ../__build +comids: + parsec-cca-valid: + - comid-parsec-cca-refval + - comid-parsec-cca-ta diff --git a/scheme/parsec-cca/test/corim/submit-parsec-cca-endorsements.sh b/scheme/parsec-cca/test/corim/submit-parsec-cca-endorsements.sh new file mode 100755 index 00000000..647fd3cd --- /dev/null +++ b/scheme/parsec-cca/test/corim/submit-parsec-cca-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-parsec-cca-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="tag:github.com/parallaxsecond,2023-03-03:cca"' --auth=none + diff --git a/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaMultRefVal.cbor b/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaMultRefVal.cbor deleted file mode 100644 index b9937db3..00000000 Binary files a/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaMultRefVal.cbor and /dev/null differ diff --git a/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor b/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor deleted file mode 100644 index f9aa8ed3..00000000 Binary files a/scheme/parsec-cca/test/corim/unsignedCorimParsecCcaComidParsecCcaRefValOne.cbor and /dev/null differ 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 fe79c66d..00000000 Binary files a/scheme/parsec-cca/test/evidence/bad_evidence.cbor and /dev/null differ diff --git a/scheme/parsec-cca/test/evidence/bad_key_endorsements.json b/scheme/parsec-cca/test/evidence/bad_key_endorsements.json deleted file mode 100644 index 7aefca23..00000000 --- a/scheme/parsec-cca/test/evidence/bad_key_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-----\nMIGkAgEBBDCKwJDJlYafYawTWPArAhomq26zhiA6xzXXzphVU4uR90xEsNWAJD77eZopPcuqCJmgBwYFK4EEACKhZANiAAQhKGfFLiuVCLCkIKkFYPOU0t+qIb3XUU/xqQGv5+H3i7EdTmb4qKOK+navajHE3oyEzi2vyZZCWLU/rXGHdPRWINERsXboMY4Rh9sCNaMY03ull/7oDg5MdioSvLPqbtQ=\n-----END PUBLIC KEY-----", - "inst-id":"Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/bad_key_header_endorsements.json b/scheme/parsec-cca/test/evidence/bad_key_header_endorsements.json deleted file mode 100644 index 5ce060e2..00000000 --- a/scheme/parsec-cca/test/evidence/bad_key_header_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 -----\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/bad_key_private_key.json b/scheme/parsec-cca/test/evidence/bad_key_private_key.json deleted file mode 100644 index d453d7b3..00000000 --- a/scheme/parsec-cca/test/evidence/bad_key_private_key.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 PRIVATE KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIShnxS4rlQiwpCCpBWDzlNLfqiG911FP\n8akBr+fh94uxHU5m+Kijivp2r2oxxN6MhM4tr8mWQli1P61xh3T0ViDREbF26DGO\nEYfbAjWjGNN7pZf+6A4OTHYqEryz6m7U\n-----END PRIVATE KEY-----", - "inst-id":"Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/compile-parsec-cca-evidence.sh b/scheme/parsec-cca/test/evidence/compile-parsec-cca-evidence.sh new file mode 100755 index 00000000..c52621b7 --- /dev/null +++ b/scheme/parsec-cca/test/evidence/compile-parsec-cca-evidence.sh @@ -0,0 +1,27 @@ +#!/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 ) +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 08c82aeb..b2375228 Binary files a/scheme/parsec-cca/test/evidence/evidence.cbor and b/scheme/parsec-cca/test/evidence/evidence.cbor differ diff --git a/scheme/parsec-cca/test/evidence/extracted.json b/scheme/parsec-cca/test/evidence/extracted.json deleted file mode 100755 index 69939249..00000000 --- a/scheme/parsec-cca/test/evidence/extracted.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "evidence": { - "cca.platform": { - "cca-platform-challenge": "tZc8touqn8VVWHhrfsZ/aeQN9bpaqSHNDCf0BYegEeo=", - "cca-platform-config": "AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY", - "cca-platform-hash-algo-id": "sha-256", - "cca-platform-implementation-id": "f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=", - "cca-platform-instance-id": "AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY", - "cca-platform-lifecycle": 12291, - "cca-platform-profile": "http://arm.com/CCA-SSD/1.0.0", - "cca-platform-service-indicator": "whatever.com", - "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": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "version": "1.2" - }, { - "measurement-type": "M2", - "measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "version": "1.2.3" - }, { - "measurement-type": "M3", - "measurement-value": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "signer-id": "BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=", - "version": "1" - }] - }, - "cca.realm": { - "cca-realm-challenge": "cqJXkxzhxf4rU34/UCEvka5SlX1AKjsp7FQO+k7L0aRgp4xorPOmOXDAEwM5y/5Y2ePbs84RCTRgx1L8iQqwIQ==", - "cca-realm-extensible-measurements": ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="], - "cca-realm-hash-algo-id": "sha-256", - "cca-realm-initial-measurement": "X5A2VVSw+obQdbbWpOpYZtsXk9S06ZO7UuVk1yefEXg=", - "cca-realm-personalization-value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "cca-realm-public-key": "BHb5iAkb5YXtQYAa7Pq4WFSMYwV+FrDmdhILvQ0vnCngVsXUGgEw65whUXiZ3CMUayjhsGK9PqSzFf0hnxy7Uoy250ykm+Fnc3NPYaHKYQMbK789kY8vlP/EIo5QkZVErg==", - "cca-realm-public-key-hash-algo-id": "sha-256" - }, - "kat": { - "akpub": "pAECIAEhWCCb/9umdTMsm7td4rLaCfgYR0qYmsIAI/gowWILqA9h2CJYIMg5wnIw3wGYQNOkXJYYb40HGT68Q6hB4N3ixGP2TEoV", - "nonce": "AAECAwQFBgc=" - } - }, - "reference-ids": ["PARSEC_CCA://0/f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA="], - "trust-anchor-ids": ["PARSEC_CCA://1/f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=/AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY"], - "tenant-id": "1" -} \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/mismatch_cfg_refval_endorsements.json b/scheme/parsec-cca/test/evidence/mismatch_cfg_refval_endorsements.json deleted file mode 100644 index eb7cfadc..00000000 --- a/scheme/parsec-cca/test/evidence/mismatch_cfg_refval_endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQID\"}}" - ] \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/mismatch_swcomp_refval_endorsements.json b/scheme/parsec-cca/test/evidence/mismatch_swcomp_refval_endorsements.json deleted file mode 100644 index 341aaba7..00000000 --- a/scheme/parsec-cca/test/evidence/mismatch_swcomp_refval_endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"CwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"DwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY\"}}" - ] \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/refval_endorsement.json b/scheme/parsec-cca/test/evidence/refval_endorsement.json deleted file mode 100644 index 26a7a08e..00000000 --- a/scheme/parsec-cca/test/evidence/refval_endorsement.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "scheme": "PARSEC_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" - } -} \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/refval_endorsements.json b/scheme/parsec-cca/test/evidence/refval_endorsements.json deleted file mode 100644 index 5eefeee1..00000000 --- a/scheme/parsec-cca/test/evidence/refval_endorsements.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"BL\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"3.4.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M1\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M2\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1.2.3\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.sw-component\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"measurement-desc\":\"sha-256\",\"measurement-type\":\"M3\",\"measurement-value\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"signer-id\":\"BwYFBAMCAQAPDg0MCwoJCBcWFRQTEhEQHx4dHBsaGRg=\",\"version\":\"1\"}}", - "{\"scheme\":\"PARSEC_CCA\",\"type\":\"REFERENCE_VALUE\",\"subType\": \"platform.config\",\"attributes\":{\"hw-model\":\"RoadRunner\",\"hw-vendor\":\"ACME\",\"impl-id\":\"f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAUFgAAAAAAAA=\",\"platform-config-label\": \"platform-config-label\",\"platform-config-id\": \"AQcGBQQDAgEADw4NDAsKCQgXFhUUExIREB8eHRwbGhkY\"}}" -] \ No newline at end of file diff --git a/scheme/parsec-cca/test/evidence/src/cca-claims.json.template b/scheme/parsec-cca/test/evidence/src/cca-claims.json.template new file mode 100644 index 00000000..383d555e --- /dev/null +++ b/scheme/parsec-cca/test/evidence/src/cca-claims.json.template @@ -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": "${KAT_HASH}", + "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/parsec-cca/test/evidence/src/ec.p256.jwk b/scheme/parsec-cca/test/evidence/src/ec.p256.jwk new file mode 100644 index 00000000..e3c07719 --- /dev/null +++ b/scheme/parsec-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/parsec-cca/test/evidence/src/ec.p384.jwk b/scheme/parsec-cca/test/evidence/src/ec.p384.jwk new file mode 100644 index 00000000..cd97e3a4 --- /dev/null +++ b/scheme/parsec-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/parsec-cca/test/evidence/src/kat.diag b/scheme/parsec-cca/test/evidence/src/kat.diag new file mode 100644 index 00000000..2fae818f --- /dev/null +++ b/scheme/parsec-cca/test/evidence/src/kat.diag @@ -0,0 +1,11 @@ +601({ + 10: h'0001020304050607', + 8: { + 1: { + 1: 2, + -1: 1, + -2: h'9BFFDBA675332C9BBB5DE2B2DA09F818474A989AC20023F828C1620BA80F61D8', + -3: h'C839C27230DF019840D3A45C96186F8D07193EBC43A841E0DDE2C463F64C4A15' + } + } +}) diff --git a/scheme/parsec-cca/test/evidence/submit-parsec-cca-evidence.sh b/scheme/parsec-cca/test/evidence/submit-parsec-cca-evidence.sh new file mode 100755 index 00000000..f20d2f4b --- /dev/null +++ b/scheme/parsec-cca/test/evidence/submit-parsec-cca-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 + +EVIDENCE_FILE=evidence.cbor +EVIDENCE_CONTENT_TYPE=application/vnd.parallaxsecond.key-attestation.cca + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /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 e8554b70..f3b74640 100644 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownClassIdType.cbor and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-class-id.cbor differ 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 581bca43..6d3430b3 100644 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyUnknownInstanceType.cbor and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-instance.cbor differ 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 cdc57c46..19af7d17 100644 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyManyKeys.cbor and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-multiple-keys.cbor differ 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 3f2d8741..2efbc8d3 100644 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoClassId.cbor and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-class-id.cbor differ 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 331f83f2..f5e9c2f1 100644 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoClass.cbor and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-class.cbor differ 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 00000000..9bec82c9 Binary files /dev/null and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-digests.cbor differ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoInstance.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-instance.cbor similarity index 82% rename from scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoInstance.cbor rename to scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-instance.cbor index aafaaa84..2c937acd 100644 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyNoInstance.cbor and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-instance.cbor differ diff --git a/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-pcr.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-pcr.cbor new file mode 100644 index 00000000..22f921dc Binary files /dev/null and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-no-pcr.cbor differ 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 00000000..d4a002b5 Binary files /dev/null and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-bad-pcr.cbor differ diff --git a/scheme/parsec-tpm/test/corim/corim-parsec-tpm-valid.cbor b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-valid.cbor new file mode 100644 index 00000000..6e489266 Binary files /dev/null and b/scheme/parsec-tpm/test/corim/corim-parsec-tpm-valid.cbor differ diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoClass.json b/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoClass.json deleted file mode 100644 index a7044203..00000000 --- a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoClass.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "tag-identity": { - "id": "99019224-57AA-44BC-BEF8-D36BDD6BD035" - }, - "entities": [ - { - "name": "Parsec", - "regid": "https://github.com/parallaxsecond", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], - "triples": { - "reference-values": [ - { - "environment": { - "instance": { - "type": "ueid", - "value": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - } - }, - "measurements": [ - { - "key": { - "type": "uint", - "value": 0 - }, - "value": { - "digests": [ - "sha-256:h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", - "sha-384:QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" - ] - } - }, - { - "key": { - "type": "uint", - "value": 1 - }, - "value": { - "digests": [ - "sha-256:rqg3uI4yCrzUdvWDmVLV4aYSwOSiJcuSBdIAcebDd0U=", - "sha-384:IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" - ] - } - } - ] - } - ] - } -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyUnknownClassIdType.json b/scheme/parsec-tpm/test/corim/src/comid-bad-class-id.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyUnknownClassIdType.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-class-id.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyUnknownInstanceType.json b/scheme/parsec-tpm/test/corim/src/comid-bad-instance.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyUnknownInstanceType.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-instance.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyManyKeys.json b/scheme/parsec-tpm/test/corim/src/comid-bad-multiple-keys.json similarity index 97% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyManyKeys.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-multiple-keys.json index 583b9e4f..e77a9d9b 100644 --- a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyManyKeys.json +++ b/scheme/parsec-tpm/test/corim/src/comid-bad-multiple-keys.json @@ -24,7 +24,7 @@ } }, "instance": { - "type": "ueid", + "type": "bytes", "value": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" } }, diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyNoClassId.json b/scheme/parsec-tpm/test/corim/src/comid-bad-no-class-id.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyNoClassId.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-no-class-id.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyNoClass.json b/scheme/parsec-tpm/test/corim/src/comid-bad-no-class.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyNoClass.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-no-class.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoDigests.json b/scheme/parsec-tpm/test/corim/src/comid-bad-no-digests.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoDigests.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-no-digests.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyNoInstance.json b/scheme/parsec-tpm/test/corim/src/comid-bad-no-instance.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyNoInstance.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-no-instance.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoPCR.json b/scheme/parsec-tpm/test/corim/src/comid-bad-no-pcr.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsNoPCR.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-no-pcr.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsUnknownPCRType.json b/scheme/parsec-tpm/test/corim/src/comid-bad-pcr.json similarity index 100% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsUnknownPCRType.json rename to scheme/parsec-tpm/test/corim/src/comid-bad-pcr.json diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsGood.json b/scheme/parsec-tpm/test/corim/src/comid-parsec-tpm-refval.json similarity index 69% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsGood.json rename to scheme/parsec-tpm/test/corim/src/comid-parsec-tpm-refval.json index ebc7ca3b..5844d5a5 100644 --- a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmPcrsGood.json +++ b/scheme/parsec-tpm/test/corim/src/comid-parsec-tpm-refval.json @@ -32,7 +32,7 @@ }, "value": { "digests": [ - "sha-256;h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", + "sha-256;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" ] } @@ -44,7 +44,19 @@ }, "value": { "digests": [ - "sha-256;rqg3uI4yCrzUdvWDmVLV4aYSwOSiJcuSBdIAcebDd0U=", + "sha-256;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "sha-384;QoS1aUymwNLPR4mguVrIAlyBjeUjBDZL580pgbLS7caFsyInfsJYGZYkE9jJssH1" + ] + } + }, + { + "key": { + "type": "uint", + "value": 2 + }, + "value": { + "digests": [ + "sha-256;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "sha-384;IQe752H8pS2VE2oTVNt6TdV7Gya+DT2nHZ6yOYazS6YVq/ZRTPNeWp6lWgMtBop4" ] } @@ -53,4 +65,4 @@ } ] } -} \ No newline at end of file +} diff --git a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyGood.json b/scheme/parsec-tpm/test/corim/src/comid-parsec-tpm-ta.json similarity index 76% rename from scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyGood.json rename to scheme/parsec-tpm/test/corim/src/comid-parsec-tpm-ta.json index 61375113..1991a4f2 100644 --- a/scheme/parsec-tpm/test/corim/src/ComidParsecTpmKeyGood.json +++ b/scheme/parsec-tpm/test/corim/src/comid-parsec-tpm-ta.json @@ -24,14 +24,14 @@ } }, "instance": { - "type": "ueid", - "value": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "type": "bytes", + "value": "AYiFVFnuuemzSkbrSMs58vaqadoEUioybRI9XFAfziEM" } }, "verification-keys": [ { "type": "pkix-base64-key", - "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE/RwSXooI8DdatPOYg/uiKm2XrtT/uEMEvqQZrwJHHcfw0c3WVzGoqL3Y/Q6xkHFfdUVqS2WWkPdKO03uw==\n-----END PUBLIC KEY-----" + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2lB1xtcIWePIt/Wwt+s8Ybp+5ji8\nt2pzGDKSOG7xTGK5gOYkcLCHz4i4L/yGzyEmBO1mZFZNuJz14X0J24+XQQ==\n-----END PUBLIC KEY-----" } ] } diff --git a/scheme/parsec-tpm/test/corim/src/corimMini.json b/scheme/parsec-tpm/test/corim/src/corim-parsec-tpm.json similarity index 54% rename from scheme/parsec-tpm/test/corim/src/corimMini.json rename to scheme/parsec-tpm/test/corim/src/corim-parsec-tpm.json index 8abf8483..ef5f2e14 100644 --- a/scheme/parsec-tpm/test/corim/src/corimMini.json +++ b/scheme/parsec-tpm/test/corim/src/corim-parsec-tpm.json @@ -1,4 +1,4 @@ { - "corim-id": "B3EC060E-2A5B-4BC2-8F71-1DAB08CE5BE9", + "corim-id": "00000000-0000-0000-6768-000000000000", "profile": "tag:github.com/parallaxsecond,2023-03-03:tpm" } diff --git a/scheme/parsec-tpm/test/corim/src/corims.yaml b/scheme/parsec-tpm/test/corim/src/corims.yaml new file mode 100644 index 00000000..ba69990b --- /dev/null +++ b/scheme/parsec-tpm/test/corim/src/corims.yaml @@ -0,0 +1,25 @@ +corim: corim-parsec-tpm +outdir: .. +workdir: ../__build +comids: + parsec-tpm-valid: + - comid-parsec-tpm-refval + - comid-parsec-tpm-ta + parsec-tpm-bad-class-id: + - comid-bad-class-id + parsec-tpm-bad-instance: + - comid-bad-instance + parsec-tpm-bad-multiple-keys: + - comid-bad-multiple-keys + parsec-tpm-bad-no-class-id: + - comid-bad-no-class-id + parsec-tpm-bad-no-class: + - comid-bad-no-class + parsec-tpm-bad-no-digests: + - comid-bad-no-digests + parsec-tpm-bad-no-instance: + - comid-bad-no-instance + parsec-tpm-bad-no-pcr: + - comid-bad-no-pcr + parsec-tpm-bad-pcr: + - comid-bad-pcr diff --git a/scheme/parsec-tpm/test/corim/submit-parsec-tpm-endorsements.sh b/scheme/parsec-tpm/test/corim/submit-parsec-tpm-endorsements.sh new file mode 100755 index 00000000..f728eadf --- /dev/null +++ b/scheme/parsec-tpm/test/corim/submit-parsec-tpm-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-parsec-tpm-valid.cbor --api-server https://localhost:9443/endorsement-provisioning/v1/submit --media-type='application/rim+cbor; profile="tag:github.com/parallaxsecond,2023-03-03:tpm"' --auth=none + diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyGood.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyGood.cbor deleted file mode 100644 index 5257ccfc..00000000 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmKeyGood.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor deleted file mode 100644 index 88caca63..00000000 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsGood.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoClass.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoClass.cbor deleted file mode 100644 index c1a90c5f..00000000 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoClass.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor deleted file mode 100644 index bd2346c9..00000000 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoDigests.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoPCR.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoPCR.cbor deleted file mode 100644 index 7730449a..00000000 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsNoPCR.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor b/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor deleted file mode 100644 index 95bbfd9c..00000000 Binary files a/scheme/parsec-tpm/test/corim/unsignedCorimMiniComidParsecTpmPcrsUnknownPCRType.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/evidence/bad_evidence.cbor b/scheme/parsec-tpm/test/evidence/bad_evidence.cbor deleted file mode 100644 index fe79c66d..00000000 Binary files a/scheme/parsec-tpm/test/evidence/bad_evidence.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/evidence/bad_key_endorsements.json b/scheme/parsec-tpm/test/evidence/bad_key_endorsements.json deleted file mode 100644 index eea5e652..00000000 --- a/scheme/parsec-tpm/test/evidence/bad_key_endorsements.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scheme": "PARSEC_TPM", - "type": "VERIFICATION_KEY", - "attributes": { - "parsec-tpm.ak-pub": "-----BEGIN PUBLIC KEY-----\nMIGkAgEBBDCKwJDJlYafYawTWPArAhomq26zhiA6xzXXzphVU4uR90xEsNWAJD77eZopPcuqCJmgBwYFK4EEACKhZANiAAQhKGfFLiuVCLCkIKkFYPOU0t+qIb3XUU/xqQGv5+H3i7EdTmb4qKOK+navajHE3oyEzi2vyZZCWLU/rXGHdPRWINERsXboMY4Rh9sCNaMY03ull/7oDg5MdioSvLPqbtQ=\n-----END PUBLIC KEY-----", - "parsec-tpm.class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c", - "parsec-tpm.instance-id": "AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn" - } -} diff --git a/scheme/parsec-tpm/test/evidence/bad_key_header_endorsements.json b/scheme/parsec-tpm/test/evidence/bad_key_header_endorsements.json deleted file mode 100644 index b3e893a4..00000000 --- a/scheme/parsec-tpm/test/evidence/bad_key_header_endorsements.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scheme": "PARSEC_TPM", - "type": "VERIFICATION_KEY", - "attributes": { - "parsec-tpm.ak-pub": "-----BEGIN -----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIShnxS4rlQiwpCCpBWDzlNLfqiG911FP\n8akBr+fh94uxHU5m+Kijivp2r2oxxN6MhM4tr8mWQli1P61xh3T0ViDREbF26DGO\nEYfbAjWjGNN7pZf+6A4OTHYqEryz6m7U\n-----END PUBLIC KEY-----", - "parsec-tpm.class-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "parsec-tpm.instance-id": "AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn" - } -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/bad_key_private_key.json b/scheme/parsec-tpm/test/evidence/bad_key_private_key.json deleted file mode 100644 index bb39cff5..00000000 --- a/scheme/parsec-tpm/test/evidence/bad_key_private_key.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scheme": "PARSEC_TPM", - "type": "VERIFICATION_KEY", - "attributes": { - "parsec-tpm.ak-pub": "-----BEGIN PRIVATE KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIShnxS4rlQiwpCCpBWDzlNLfqiG911FP\n8akBr+fh94uxHU5m+Kijivp2r2oxxN6MhM4tr8mWQli1P61xh3T0ViDREbF26DGO\nEYfbAjWjGNN7pZf+6A4OTHYqEryz6m7U\n-----END PRIVATE KEY-----", - "parsec-tpm.class-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "parsec-tpm.instance-id": "AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn" - } -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/bad_ta_endorsements.json b/scheme/parsec-tpm/test/evidence/bad_ta_endorsements.json deleted file mode 100644 index 1c544219..00000000 --- a/scheme/parsec-tpm/test/evidence/bad_ta_endorsements.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scheme": "PARSEC_TPM", - "type": "VERIFICATION_KEY", - "attributes": { - "parsec-tpm.ak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "parsec-tpm.class-id": 12456, - "parsec-tpm.instance-id": "AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn" - } -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/compile-parsec-tpm-evidence.sh b/scheme/parsec-tpm/test/evidence/compile-parsec-tpm-evidence.sh new file mode 100755 index 00000000..abed8c55 --- /dev/null +++ b/scheme/parsec-tpm/test/evidence/compile-parsec-tpm-evidence.sh @@ -0,0 +1,9 @@ +#!/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 ) +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 7c03a9e3..00000000 Binary files a/scheme/parsec-tpm/test/evidence/evidence1.cbor and /dev/null differ diff --git a/scheme/parsec-tpm/test/evidence/extracted.json b/scheme/parsec-tpm/test/evidence/extracted.json deleted file mode 100644 index 9b78c954..00000000 --- a/scheme/parsec-tpm/test/evidence/extracted.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "evidence": { - "kat": { - "certInfo": "/1RDR4AXACIAC6ILnhL7TgUH8devSpSSlDy+rogdt87+BA7f5Ifv81T1AAjerb7v3q2+7wAAAAAa3bPMCQx1d/2Inc4BWE+O8ye8r7oAIgALZrzCaSFqZytlxQdDMOmokNP/0u14rhKimGr2KQ4Fe6QAIgALRod5sOGP/Q68ys58WrElrIgJorCH4Jz8bxWOETEzoBQ=", - "kid": "Ad6tvu/erb7v3q2+796tvu8=", - "pubArea": "ACMACwAEAHIAAAAQABgACwADABAAIKkHw8AhAqJUnISiuLITDp9pZnGTkaTHKjV3laH5XoOKACBFgkit3/P0rN22S9KSj2m4Ef8Nhi4z54igcEtqqClQIA==", - "sig": "ABgADAAwPmycQJcUnUGB8wTdeKThb4R4p9cZCi1xEdULd6HkTiDjNizNbFeZraD9kHUmJmUaADAYXLWMXOtUv6RkivCDMfvsnJJh4ipA0CykzfXCS8+9I7ughfXwpZyDjuf2AjsEzwM=", - "tpmVer": "2.0" - }, - "pat": { - "attestInfo": "/1RDR4AYAAQAAABkABNBQkFCQUJBQkFCQUJBQkFCQUJBAAAAAAAAAAMAAAAEAAAABQYAAAAAAAAABwAAAAEACwMOAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "kid": "Ad6tvu/erb7v3q2+796tvu8=", - "sig": "ABgACwAw7EQrGzA22otxCVQIkn+5UdJ+Yttnw2muhFvqa2D5LROVoi/nUasvhDU18yFgCEzPADAieV9wS6JXF0eRPPkOVgD7qAT33L4K/V99G2XkLyhW3v+Ur8fC01VntccdgbvzAcQ=", - "tpmVer": "2.0" - } - }, - "reference-ids": ["PARSEC_TPM://1/YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE="], - "trust-anchor-ids": ["PARSEC_TPM://1/AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn"], - "tenant-id": "1" -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/match_pcr_digest_endorsements.json b/scheme/parsec-tpm/test/evidence/match_pcr_digest_endorsements.json deleted file mode 100644 index ce17bb4e..00000000 --- a/scheme/parsec-tpm/test/evidence/match_pcr_digest_endorsements.json +++ /dev/null @@ -1,5 +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}}", - "{\"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}}" -] \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/matched_extracted.json b/scheme/parsec-tpm/test/evidence/matched_extracted.json deleted file mode 100644 index 45ef7fb0..00000000 --- a/scheme/parsec-tpm/test/evidence/matched_extracted.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "evidence": { - "kat": { - "certInfo": "/1RDR4AXACIAC6ILnhL7TgUH8devSpSSlDy+rogdt87+BA7f5Ifv81T1AAjerb7v3q2+7wAAAAAa3bPMCQx1d/2Inc4BWE+O8ye8r7oAIgALZrzCaSFqZytlxQdDMOmokNP/0u14rhKimGr2KQ4Fe6QAIgALRod5sOGP/Q68ys58WrElrIgJorCH4Jz8bxWOETEzoBQ=", - "kid": "Ad6tvu/erb7v3q2+796tvu8=", - "pubArea": "ACMACwAEAHIAAAAQABgACwADABAAIKkHw8AhAqJUnISiuLITDp9pZnGTkaTHKjV3laH5XoOKACBFgkit3/P0rN22S9KSj2m4Ef8Nhi4z54igcEtqqClQIA==", - "sig": "ABgADAAwPmycQJcUnUGB8wTdeKThb4R4p9cZCi1xEdULd6HkTiDjNizNbFeZraD9kHUmJmUaADAYXLWMXOtUv6RkivCDMfvsnJJh4ipA0CykzfXCS8+9I7ughfXwpZyDjuf2AjsEzwM=", - "tpmVer": "2.0" - }, - "pat": { - "attestInfo": "/1RDR4AYACIAC0j2LACF3t8/Zb3kGEbtmfeIxhCjlkg4UglxRL2k/IO6AAQwMDAwAAAAADMkYhlZ5GOrZIk36AFcB54IPCa0UQAAAAEACwMHAAAAIC6pq5GY0WOAB0AM0sO+8cx0W4ZLdgEaDhvFIYCsZFLU", - "kid": "Ad6tvu/erb7v3q2+796tvu8=", - "sig": "ABgACwAw7EQrGzA22otxCVQIkn+5UdJ+Yttnw2muhFvqa2D5LROVoi/nUasvhDU18yFgCEzPADAieV9wS6JXF0eRPPkOVgD7qAT33L4K/V99G2XkLyhW3v+Ur8fC01VntccdgbvzAcQ=", - "tpmVer": "2.0" - } - }, - "reference-ids": ["PARSEC_TPM://1/YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE="], - "trust-anchor-ids": ["PARSEC_TPM://1/AagIEsUMYDNxd1p5UuAACkxJGfJf9rcUZ/oyRFHDcAxn"], - "tenant-id": "1" -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/refval-endorsements.json b/scheme/parsec-tpm/test/evidence/refval-endorsements.json deleted file mode 100644 index 7fa33020..00000000 --- a/scheme/parsec-tpm/test/evidence/refval-endorsements.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "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 - } -} \ No newline at end of file diff --git a/scheme/parsec-tpm/test/evidence/src/evidence.diag b/scheme/parsec-tpm/test/evidence/src/evidence.diag new file mode 100644 index 00000000..682cca40 --- /dev/null +++ b/scheme/parsec-tpm/test/evidence/src/evidence.diag @@ -0,0 +1,15 @@ +{ + "kat": { + "tpmVer": "2.0", + "sig": h'0018000B00202975ED737C0E4609BAFB8A96F63DDFC8B745B793620018198859BB695F58E24300201A23DF81503C01A4351257E513FAD6924542B1ABDBAE35E2D0DB683AE73E513E', + "kid": h'0188855459EEB9E9B34A46EB48CB39F2F6AA69DA04522A326D123D5C501FCE210C', + "pubArea": h'0023000B00040072000000100018000B000300100020A907C3C02102A2549C84A2B8B2130E9F6966719391A4C72A357795A1F95E838A0020458248ADDFF3F4ACDDB64BD2928F69B811FF0D862E33E788A0704B6AA8295020', + "certInfo": h'FF54434780170022000BA20B9E12FB4E0507F1D7AF4A9492943CBEAE881DB7CEFE040EDFE487EFF354F50008DEADBEEFDEADBEEF000000001ADDB3CC090C7577FD889DCE01584F8EF327BCAFBA0022000B66BCC269216A672B65C5074330E9A890D3FFD2ED78AE12A2986AF6290E057BA40022000B468779B0E18FFD0EBCCACE7C5AB125AC8809A2B087E09CFC6F158E113133A014' + }, + "pat": { + "tpmVer": "2.0", + "sig": h'0018000B0020A771B57D791FDC8269D64F3727CA0FFD55D53E7E22FC6D9FECF7EB2BFF27A706002016BEA7499F78D61AE31E2569F771ABBFB86619DD0E6CCAC9CC664CE62A629929', + "kid": h'0188855459EEB9E9B34A46EB48CB39F2F6AA69DA04522A326D123D5C501FCE210C', + "attestInfo": h'FF54434780180022000BA20B9E12FB4E0507F1D7AF4A9492943CBEAE881DB7CEFE040EDFE487EFF354F50008DEADBEEFDEADBEEF000000001ADDB3CF090C7577FD889DCE01584F8EF327BCAFBA00000001000B0307000000202EA9AB9198D1638007400CD2C3BEF1CC745B864B76011A0E1BC52180AC6452D4' + } +} diff --git a/scheme/parsec-tpm/test/evidence/submit-parsec-tpm-evidence.sh b/scheme/parsec-tpm/test/evidence/submit-parsec-tpm-evidence.sh new file mode 100755 index 00000000..a84246bc --- /dev/null +++ b/scheme/parsec-tpm/test/evidence/submit-parsec-tpm-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 + +EVIDENCE_FILE=evidence.cbor +EVIDENCE_CONTENT_TYPE=application/vnd.parallaxsecond.key-attestation.tpm + +THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /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 66d9c664..017cc750 100644 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoImplID.cbor and b/scheme/psa-iot/test/corim/corim-psa-bad-class.cbor differ 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 00000000..f883c9c8 Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-bad-instance.cbor differ diff --git a/scheme/psa-iot/test/corim/corim-psa-bad-refval-instance.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-refval-instance.cbor new file mode 100644 index 00000000..62c5ff27 Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-bad-refval-instance.cbor differ 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 00000000..8d305109 Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-bad-refval-mkey.cbor differ diff --git a/scheme/psa-iot/test/corim/corim-psa-bad-refval-mval.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-refval-mval.cbor new file mode 100644 index 00000000..71b45b82 Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-bad-refval-mval.cbor differ diff --git a/scheme/psa-iot/test/corim/corim-psa-bad-ta-cert.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-ta-cert.cbor new file mode 100644 index 00000000..7a238750 Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-bad-ta-cert.cbor differ diff --git a/scheme/psa-iot/test/corim/corim-psa-bad-ta-no-instance.cbor b/scheme/psa-iot/test/corim/corim-psa-bad-ta-no-instance.cbor new file mode 100644 index 00000000..9f2cf10e Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-bad-ta-no-instance.cbor differ 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 00000000..130da979 Binary files /dev/null and b/scheme/psa-iot/test/corim/corim-psa-valid.cbor differ diff --git a/scheme/psa-iot/test/corim/src/ComidPsaMultIak.json b/scheme/psa-iot/test/corim/src/ComidPsaMultIak.json deleted file mode 100644 index fe87dc18..00000000 --- a/scheme/psa-iot/test/corim/src/ComidPsaMultIak.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "lang": "en-GB", - "tag-identity": { - "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", - "version": 0 - }, - "entities": [ - { - "name": "ACME Ltd.", - "regid": "https://acme.example", - "roles": [ - "tagCreator", - "creator", - "maintainer" - ] - } - ], - "triples": { - "attester-verification-keys": [ - { - "environment": { - "class": { - "id": { - "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" - }, - "vendor": "ACME", - "model": "RoadRunner" - }, - "instance": { - "type": "ueid", - "value": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } - }, - "verification-keys": [ - { - "type": "pkix-base64-key", - "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" - }, - { - "type": "pkix-base64-key", - "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFn0taoAwR3PmrKkYLtAsD9o05KSM6mbgfNCgpuL0g6VpTHkZl73wk5BDxoV7n+Oeee0iIqkW3HMZT3ETiniJdg==\n-----END PUBLIC KEY-----" - } - ] - } - ] - } -} diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValNoImplID.json b/scheme/psa-iot/test/corim/src/ComidPsaRefValNoImplID.json deleted file mode 100644 index 183c77aa..00000000 --- a/scheme/psa-iot/test/corim/src/ComidPsaRefValNoImplID.json +++ /dev/null @@ -1,52 +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": "uuid", - "value": "DD6661F0-0928-4401-966B-589EA74E3272" - }, - "model": "FMC", - "layer": 0, - "index": 0 - } - }, - "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=" - ] - } - } - ] - } - ] - } -} diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValNoMkey.json b/scheme/psa-iot/test/corim/src/ComidPsaRefValNoMkey.json deleted file mode 100644 index f7a38099..00000000 --- a/scheme/psa-iot/test/corim/src/ComidPsaRefValNoMkey.json +++ /dev/null @@ -1,52 +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": [ - { - "value": { - "op-flags": [ - "notSecure", - "debug" - ], - "digests": [ - "sha-256:RKozavTLFKh5Qy5T3WVxx/qbzK+3X0iCWSYtbqOk2Rs=" - ], - "svn": { - "type": "exact-value", - "value": 10 - } - } - } - ] - } - ] - } - } - diff --git a/scheme/psa-iot/test/corim/src/ComidPsaRefValOne.cbor b/scheme/psa-iot/test/corim/src/ComidPsaRefValOne.cbor deleted file mode 100644 index a0db3ba5..00000000 Binary files a/scheme/psa-iot/test/corim/src/ComidPsaRefValOne.cbor and /dev/null differ 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 5cc1c8c0..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubNoUeID.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor deleted file mode 100644 index 83fd80d5..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubOne.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor deleted file mode 100644 index fd1d3698..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaIakPubTwo.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaMultIak.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaMultIak.cbor deleted file mode 100644 index b1c7efd5..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaMultIak.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValMultDigest.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValMultDigest.cbor deleted file mode 100644 index 866a05fc..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValMultDigest.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor deleted file mode 100644 index 8c0278f8..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoImplID.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoMkey.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoMkey.cbor deleted file mode 100644 index 7af08fe7..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValNoMkey.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOne.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOne.cbor deleted file mode 100644 index 19a35e04..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOne.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor deleted file mode 100644 index 54b3026a..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValOnlyMandIDAttr.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValThree.cbor b/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValThree.cbor deleted file mode 100644 index 34e54367..00000000 Binary files a/scheme/psa-iot/test/corim/unsignedCorimMiniComidPsaRefValThree.cbor and /dev/null differ diff --git a/scheme/psa-iot/test/token/compile-psa-evidence.sh b/scheme/psa-iot/test/token/compile-psa-evidence.sh new file mode 100755 index 00000000..9eff887d --- /dev/null +++ b/scheme/psa-iot/test/token/compile-psa-evidence.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Copyright 2026 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 +evcli psa create --allow-invalid --claims=psa.good.json --key=ec.p256.jwk --token=psa.good.cose diff --git a/scheme/psa-iot/test/token/ec.p256.jwk b/scheme/psa-iot/test/token/ec.p256.jwk new file mode 100644 index 00000000..e3c07719 --- /dev/null +++ b/scheme/psa-iot/test/token/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/psa-iot/test/token/psa.good.cose b/scheme/psa-iot/test/token/psa.good.cose new file mode 100644 index 00000000..f1ed542e Binary files /dev/null and b/scheme/psa-iot/test/token/psa.good.cose differ 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 068ea6bb..c1da1295 100644 Binary files a/scheme/riot/test/TrustAnchor.pem and b/scheme/riot/test/corim/corim-riot-bad-no-vendor.cbor differ 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 00000000..8e41cd9c Binary files /dev/null and b/scheme/riot/test/corim/corim-riot-bad-refvals.cbor differ diff --git a/scheme/riot/test/corim/corim-riot-bad-wrong-key-type.cbor b/scheme/riot/test/corim/corim-riot-bad-wrong-key-type.cbor new file mode 100644 index 00000000..83e7e48e Binary files /dev/null and b/scheme/riot/test/corim/corim-riot-bad-wrong-key-type.cbor differ 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 00000000..20223344 Binary files /dev/null and b/scheme/riot/test/corim/corim-riot-bad-wrong-vendor.cbor differ 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 00000000..5f74f760 Binary files /dev/null and b/scheme/riot/test/corim/corim-riot-valid.cbor differ 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 00000000..7cba40ec Binary files /dev/null and b/scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-key.cbor differ diff --git a/scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-no-key.cbor b/scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-no-key.cbor new file mode 100644 index 00000000..cae7b931 Binary files /dev/null and b/scheme/sevsnp/test/corim/corim-sevsnp-bad-refval-no-key.cbor differ diff --git a/scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-model.cbor b/scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-model.cbor new file mode 100644 index 00000000..a3e312ee Binary files /dev/null and b/scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-model.cbor differ 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 00000000..38963091 Binary files /dev/null and b/scheme/sevsnp/test/corim/corim-sevsnp-bad-ta-no-vendor.cbor differ 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 00000000..53b3cf1b Binary files /dev/null and b/scheme/sevsnp/test/corim/corim-sevsnp-valid.cbor differ 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 11aba391..00000000 Binary files a/scheme/sevsnp/test/corim/unsignedCorimSevSnp.cbor and /dev/null differ 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 4f5ea9c0..00000000 Binary files a/scheme/sevsnp/test/refval-prov.cbor and /dev/null differ 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 00000000..76a84973 Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-class.cbor differ 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 00000000..962db712 Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-instance.cbor differ 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 00000000..6ca81649 Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-digests.cbor differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKMult.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-keys.cbor similarity index 67% rename from scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKMult.cbor rename to scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-keys.cbor index 3a201b39..69cedfd2 100644 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKMult.cbor and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-keys.cbor differ diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-measurements.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-measurements.cbor new file mode 100644 index 00000000..beb6d8af Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-multiple-measurements.cbor differ 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 00000000..7da09b5f Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-digest.cbor differ 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 00000000..07cc9047 Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-bad-no-instance.cbor differ diff --git a/scheme/tpm-enacttrust/test/corim/corim-enacttrust-valid.cbor b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-valid.cbor new file mode 100644 index 00000000..8264ae72 Binary files /dev/null and b/scheme/tpm-enacttrust/test/corim/corim-enacttrust-valid.cbor differ 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 f7f93964..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKBadInst.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor deleted file mode 100644 index 3f5de9a2..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustAKOne.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustBadInst.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustBadInst.cbor deleted file mode 100644 index 0953ca23..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustBadInst.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenOne.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenOne.cbor deleted file mode 100644 index ebecb47e..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenOne.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor deleted file mode 100644 index d0c27f53..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustGoldenTwo.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor deleted file mode 100644 index d18bf630..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustMultDigest.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor deleted file mode 100644 index fd7dafdb..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoDigest.cbor and /dev/null differ diff --git a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor b/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor deleted file mode 100644 index 131c3cb9..00000000 Binary files a/scheme/tpm-enacttrust/test/corim/unsignedCorimMiniComidTpmEnactTrustNoInst.cbor and /dev/null differ 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 +}