From 777571e7ec56e9bdfa847ed90bfc37c0648d5e9d Mon Sep 17 00:00:00 2001 From: Kallal Mukherjee Date: Tue, 23 Sep 2025 16:52:23 +0000 Subject: [PATCH 1/3] Fix integration tests: Convert URL-safe base64 nonces to standard base64 for PSA tokens - PSA evidence token generation (evcli psa create) expects standard base64 nonces - Server now returns URL-safe base64 nonces in challenge-response sessions - Added conversion from URL-safe to standard base64 for PSA claims generation - Matches existing conversion logic already used for CCA tokens - Resolves 'illegal base64 data' errors in integration tests Signed-off-by: Kallal Mukherjee --- integration-tests/utils/generators.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/utils/generators.py b/integration-tests/utils/generators.py index 83a2368a..2fed7287 100644 --- a/integration-tests/utils/generators.py +++ b/integration-tests/utils/generators.py @@ -128,9 +128,11 @@ def generate_evidence(scheme, evidence, nonce, signing, outname): if scheme == 'psa' and nonce: claims_file = f'{GENDIR}/claims/{scheme}.{evidence}.json' + # convert nonce from base64url to base64 + translated_nonce = nonce.replace('-', '+').replace('_', '/') update_json( f'data/claims/{scheme}.{evidence}.json', - {f'{scheme}-nonce': nonce}, + {f'{scheme}-nonce': translated_nonce}, claims_file, ) elif scheme == 'cca' and nonce: From 2f48d8c0492da99072df531888b7649f3433240c Mon Sep 17 00:00:00 2001 From: Kallal Mukherjee Date: Tue, 23 Sep 2025 18:47:32 +0000 Subject: [PATCH 2/3] fix: skip empty reference value IDs in TrustedServices.GetAttestation Fixes #42. When attestation schemes return empty reference value IDs, the GetAttestation method now skips them before calling kvstore.Get() to avoid 'the supplied key is empty' errors. This commonly occurs when no software components are provisioned in trust anchors, causing handlers to return []string{""} for missing software reference IDs. Signed-off-by: GitHub Copilot Signed-off-by: Kallal Mukherjee --- vts/trustedservices/trustedservices_grpc.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vts/trustedservices/trustedservices_grpc.go b/vts/trustedservices/trustedservices_grpc.go index 57af5653..7a4caee5 100644 --- a/vts/trustedservices/trustedservices_grpc.go +++ b/vts/trustedservices/trustedservices_grpc.go @@ -442,6 +442,11 @@ func (o *GRPC) GetAttestation( var multEndorsements []string for _, refvalID := range appraisal.EvidenceContext.ReferenceIds { + // Skip empty reference IDs (can occur when no software components are provisioned) + if refvalID == "" { + o.logger.Debugw("skipping empty reference ID", "refvalID", refvalID) + continue + } endorsements, err := o.EnStore.Get(refvalID) if err != nil && !errors.Is(err, kvstore.ErrKeyNotFound) { From ac343f69211cb7d260d8ca4aecbca389a22c7067 Mon Sep 17 00:00:00 2001 From: Kallal Mukherjee Date: Thu, 2 Oct 2025 01:38:42 +0000 Subject: [PATCH 3/3] fix: Filter empty reference IDs at source instead of in loop This addresses the reviewer feedback from @setrofim about treating the root cause rather than symptoms. Empty reference IDs are now filtered immediately after GetRefValueIDs() to ensure EvidenceContext.ReferenceIds never contains empty strings, rather than skipping them later in the loop. This is a cleaner approach that prevents the issue from propagating throughout the system and maintains data integrity at the source. Signed-off-by: Kallal Mukherjee --- vts/trustedservices/trustedservices_grpc.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/vts/trustedservices/trustedservices_grpc.go b/vts/trustedservices/trustedservices_grpc.go index 7a4caee5..9b90b99c 100644 --- a/vts/trustedservices/trustedservices_grpc.go +++ b/vts/trustedservices/trustedservices_grpc.go @@ -428,13 +428,21 @@ func (o *GRPC) GetAttestation( return o.finalize(appraisal, err) } + // Filter out empty reference IDs (can occur when no software components are provisioned) + filteredReferenceIDs := make([]string, 0, len(referenceIDs)) + for _, refID := range referenceIDs { + if refID != "" { + filteredReferenceIDs = append(filteredReferenceIDs, refID) + } + } + appraisal.EvidenceContext.Evidence, err = structpb.NewStruct(claims) if err != nil { err = fmt.Errorf("unserializable claims in result: %w", err) return o.finalize(appraisal, err) } - appraisal.EvidenceContext.ReferenceIds = referenceIDs + appraisal.EvidenceContext.ReferenceIds = filteredReferenceIDs o.logger.Debugw("constructed evidence context", "software-id", appraisal.EvidenceContext.ReferenceIds, @@ -442,11 +450,6 @@ func (o *GRPC) GetAttestation( var multEndorsements []string for _, refvalID := range appraisal.EvidenceContext.ReferenceIds { - // Skip empty reference IDs (can occur when no software components are provisioned) - if refvalID == "" { - o.logger.Debugw("skipping empty reference ID", "refvalID", refvalID) - continue - } endorsements, err := o.EnStore.Get(refvalID) if err != nil && !errors.Is(err, kvstore.ErrKeyNotFound) {