From d273249f03b9e705936b38374253173771cd6937 Mon Sep 17 00:00:00 2001 From: Siyuan Ren Date: Mon, 11 May 2026 09:12:58 +0000 Subject: [PATCH] Add golden tests to the current OpenID4VP matcher TAG=agy CONV=a1593f60-9757-49cc-9ce0-d04dcaed1d5a --- matcher/.gitignore | 2 + matcher/Makefile | 37 ++ matcher/base64.c | 1 + matcher/index.md | 117 +++++ matcher/openid4vp1_0.c | 10 +- matcher/test_plan.md | 339 +++++++++++++ matcher/test_runner.cc | 438 +++++++++++++++++ matcher/testdata/TC07_MdocMatch_expected.json | 139 ++++++ matcher/testdata/TC07_MdocMatch_request.json | 20 + .../testdata/TC08_MdocMismatch_expected.json | 4 + .../testdata/TC08_MdocMismatch_request.json | 20 + .../testdata/TC09_SdjwtMatch_expected.json | 53 +++ matcher/testdata/TC09_SdjwtMatch_request.json | 22 + .../testdata/TC10_SdjwtMismatch_expected.json | 4 + .../testdata/TC10_SdjwtMismatch_request.json | 22 + .../TC11_InlineIssuanceFallback_expected.json | 139 ++++++ .../TC11_InlineIssuanceFallback_request.json | 21 + .../testdata/TC12_MissingFormat_expected.json | 4 + .../testdata/TC12_MissingFormat_request.json | 22 + .../TC13_ReturnAllClaims_expected.json | 139 ++++++ .../TC13_ReturnAllClaims_request.json | 20 + .../TC14_MatchSpecificClaims_expected.json | 81 ++++ .../TC14_MatchSpecificClaims_request.json | 28 ++ .../TC15_MatchNestedClaims_expected.json | 45 ++ .../TC15_MatchNestedClaims_request.json | 31 ++ .../TC16_FailMissingClaims_expected.json | 18 + .../TC16_FailMissingClaims_request.json | 30 ++ .../TC17_MatchClaimValuesBool_expected.json | 81 ++++ .../TC17_MatchClaimValuesBool_request.json | 31 ++ .../TC18_FailClaimValuesBool_expected.json | 45 ++ .../TC18_FailClaimValuesBool_request.json | 31 ++ .../TC19_MatchClaimValuesInt_expected.json | 45 ++ .../TC19_MatchClaimValuesInt_request.json | 32 ++ .../TC20_FailClaimValuesInt_expected.json | 18 + .../TC20_FailClaimValuesInt_request.json | 31 ++ .../TC21_MatchFirstClaimSet_expected.json | 81 ++++ .../TC21_MatchFirstClaimSet_request.json | 44 ++ .../TC22_MatchSecondClaimSet_expected.json | 81 ++++ .../TC22_MatchSecondClaimSet_request.json | 44 ++ .../TC23_FailAllClaimSets_expected.json | 18 + .../TC23_FailAllClaimSets_request.json | 44 ++ .../TC24_DcqlQuerySingle_expected.json | 139 ++++++ .../TC24_DcqlQuerySingle_request.json | 20 + .../TC25_DcqlQuerySetMatch_expected.json | 39 ++ .../TC25_DcqlQuerySetMatch_request.json | 31 ++ ...C26_DcqlQuerySetFailRequired_expected.json | 4 + ...TC26_DcqlQuerySetFailRequired_request.json | 32 ++ ...C27_DcqlQuerySetFailOptional_expected.json | 125 +++++ ...TC27_DcqlQuerySetFailOptional_request.json | 47 ++ ...lQueryComplexOverlappingSets_expected.json | 179 +++++++ ...qlQueryComplexOverlappingSets_request.json | 85 ++++ ...cqlQueryOpenID4VPSpecExample_expected.json | 131 +++++ ...DcqlQueryOpenID4VPSpecExample_request.json | 154 ++++++ .../TC30_ParseV1Unsigned_expected.json | 139 ++++++ .../TC30_ParseV1Unsigned_request.json | 20 + .../testdata/TC31_ParseV1Signed_expected.json | 139 ++++++ .../testdata/TC31_ParseV1Signed_request.json | 10 + .../TC32_ExtractPaymentSca1_expected.json | 79 +++ .../TC32_ExtractPaymentSca1_request.json | 23 + .../TC33_ExtractPaymentDetails_expected.json | 79 +++ .../TC33_ExtractPaymentDetails_request.json | 23 + .../TC34_ExtractPaymentGeneric_expected.json | 79 +++ .../TC34_ExtractPaymentGeneric_request.json | 23 + .../TC35_WasmAddEntryToSet_expected.json | 139 ++++++ .../TC35_WasmAddEntryToSet_request.json | 20 + .../testdata/TC36_WasmPaymentV2_expected.json | 79 +++ .../testdata/TC36_WasmPaymentV2_request.json | 23 + .../TC37_WasmMetadataText_expected.json | 139 ++++++ .../TC37_WasmMetadataText_request.json | 20 + matcher/testdata/registry.json | 449 ++++++++++++++++++ 70 files changed, 4896 insertions(+), 5 deletions(-) create mode 100644 matcher/.gitignore create mode 100644 matcher/Makefile create mode 100644 matcher/index.md create mode 100644 matcher/test_plan.md create mode 100644 matcher/test_runner.cc create mode 100644 matcher/testdata/TC07_MdocMatch_expected.json create mode 100644 matcher/testdata/TC07_MdocMatch_request.json create mode 100644 matcher/testdata/TC08_MdocMismatch_expected.json create mode 100644 matcher/testdata/TC08_MdocMismatch_request.json create mode 100644 matcher/testdata/TC09_SdjwtMatch_expected.json create mode 100644 matcher/testdata/TC09_SdjwtMatch_request.json create mode 100644 matcher/testdata/TC10_SdjwtMismatch_expected.json create mode 100644 matcher/testdata/TC10_SdjwtMismatch_request.json create mode 100644 matcher/testdata/TC11_InlineIssuanceFallback_expected.json create mode 100644 matcher/testdata/TC11_InlineIssuanceFallback_request.json create mode 100644 matcher/testdata/TC12_MissingFormat_expected.json create mode 100644 matcher/testdata/TC12_MissingFormat_request.json create mode 100644 matcher/testdata/TC13_ReturnAllClaims_expected.json create mode 100644 matcher/testdata/TC13_ReturnAllClaims_request.json create mode 100644 matcher/testdata/TC14_MatchSpecificClaims_expected.json create mode 100644 matcher/testdata/TC14_MatchSpecificClaims_request.json create mode 100644 matcher/testdata/TC15_MatchNestedClaims_expected.json create mode 100644 matcher/testdata/TC15_MatchNestedClaims_request.json create mode 100644 matcher/testdata/TC16_FailMissingClaims_expected.json create mode 100644 matcher/testdata/TC16_FailMissingClaims_request.json create mode 100644 matcher/testdata/TC17_MatchClaimValuesBool_expected.json create mode 100644 matcher/testdata/TC17_MatchClaimValuesBool_request.json create mode 100644 matcher/testdata/TC18_FailClaimValuesBool_expected.json create mode 100644 matcher/testdata/TC18_FailClaimValuesBool_request.json create mode 100644 matcher/testdata/TC19_MatchClaimValuesInt_expected.json create mode 100644 matcher/testdata/TC19_MatchClaimValuesInt_request.json create mode 100644 matcher/testdata/TC20_FailClaimValuesInt_expected.json create mode 100644 matcher/testdata/TC20_FailClaimValuesInt_request.json create mode 100644 matcher/testdata/TC21_MatchFirstClaimSet_expected.json create mode 100644 matcher/testdata/TC21_MatchFirstClaimSet_request.json create mode 100644 matcher/testdata/TC22_MatchSecondClaimSet_expected.json create mode 100644 matcher/testdata/TC22_MatchSecondClaimSet_request.json create mode 100644 matcher/testdata/TC23_FailAllClaimSets_expected.json create mode 100644 matcher/testdata/TC23_FailAllClaimSets_request.json create mode 100644 matcher/testdata/TC24_DcqlQuerySingle_expected.json create mode 100644 matcher/testdata/TC24_DcqlQuerySingle_request.json create mode 100644 matcher/testdata/TC25_DcqlQuerySetMatch_expected.json create mode 100644 matcher/testdata/TC25_DcqlQuerySetMatch_request.json create mode 100644 matcher/testdata/TC26_DcqlQuerySetFailRequired_expected.json create mode 100644 matcher/testdata/TC26_DcqlQuerySetFailRequired_request.json create mode 100644 matcher/testdata/TC27_DcqlQuerySetFailOptional_expected.json create mode 100644 matcher/testdata/TC27_DcqlQuerySetFailOptional_request.json create mode 100644 matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_expected.json create mode 100644 matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_request.json create mode 100644 matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_expected.json create mode 100644 matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_request.json create mode 100644 matcher/testdata/TC30_ParseV1Unsigned_expected.json create mode 100644 matcher/testdata/TC30_ParseV1Unsigned_request.json create mode 100644 matcher/testdata/TC31_ParseV1Signed_expected.json create mode 100644 matcher/testdata/TC31_ParseV1Signed_request.json create mode 100644 matcher/testdata/TC32_ExtractPaymentSca1_expected.json create mode 100644 matcher/testdata/TC32_ExtractPaymentSca1_request.json create mode 100644 matcher/testdata/TC33_ExtractPaymentDetails_expected.json create mode 100644 matcher/testdata/TC33_ExtractPaymentDetails_request.json create mode 100644 matcher/testdata/TC34_ExtractPaymentGeneric_expected.json create mode 100644 matcher/testdata/TC34_ExtractPaymentGeneric_request.json create mode 100644 matcher/testdata/TC35_WasmAddEntryToSet_expected.json create mode 100644 matcher/testdata/TC35_WasmAddEntryToSet_request.json create mode 100644 matcher/testdata/TC36_WasmPaymentV2_expected.json create mode 100644 matcher/testdata/TC36_WasmPaymentV2_request.json create mode 100644 matcher/testdata/TC37_WasmMetadataText_expected.json create mode 100644 matcher/testdata/TC37_WasmMetadataText_request.json create mode 100644 matcher/testdata/registry.json diff --git a/matcher/.gitignore b/matcher/.gitignore new file mode 100644 index 0000000..6481fcd --- /dev/null +++ b/matcher/.gitignore @@ -0,0 +1,2 @@ +test_runner +*.o diff --git a/matcher/Makefile b/matcher/Makefile new file mode 100644 index 0000000..05d81ef --- /dev/null +++ b/matcher/Makefile @@ -0,0 +1,37 @@ +CXX = g++ +CC = gcc +CXXFLAGS = -std=c++17 -Wall -Wextra -g -I. -I/usr/include/doctest -I/usr/include/nlohmann +CFLAGS = -Wall -Wextra -g -I. -Wno-unused-variable -Wno-unused-but-set-variable -Wno-format-overflow + +# Common objects +COMMON_OBJS = dcql.o openid4vp1_0.o base64.o cJSON/cJSON.o issuance/provision.o + +# Tests +test_runner: test_runner.o dcql.o openid4vp1_0.o base64.o cJSON/cJSON.o + $(CXX) $(CXXFLAGS) -o $@ $^ + +test: test_runner + ./test_runner + +test_runner.o: test_runner.cc + $(CXX) $(CXXFLAGS) -c $< -o $@ + +dcql.o: dcql.c + $(CC) $(CFLAGS) -c $< -o $@ + +openid4vp1_0.o: openid4vp1_0.c + $(CC) $(CFLAGS) -c $< -o $@ + +base64.o: base64.c + $(CC) $(CFLAGS) -c $< -o $@ + +cJSON/cJSON.o: cJSON/cJSON.c + $(CC) $(CFLAGS) -c $< -o $@ + +issuance/provision.o: issuance/provision.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f *.o cJSON/*.o issuance/*.o test_runner + +.PHONY: test clean diff --git a/matcher/base64.c b/matcher/base64.c index 0bd2b95..6d3dfbc 100644 --- a/matcher/base64.c +++ b/matcher/base64.c @@ -43,6 +43,7 @@ int B64DecodeURL(char* input, char** output) { output_len--; } + buffer[output_len] = '\0'; return output_len; } diff --git a/matcher/index.md b/matcher/index.md new file mode 100644 index 0000000..e949bc7 --- /dev/null +++ b/matcher/index.md @@ -0,0 +1,117 @@ +# OpenID4VP Matcher: Comprehensive Code Index + +## 1. Registry Binary Format +The registry blob is a custom binary format: +- **Header**: 4 bytes (Little-endian `int`) representing the offset from the start of the blob to the beginning of the JSON metadata. +- **Icon Section**: Raw PNG bytes located between the header and the JSON metadata. +- **Metadata Section**: UTF-8 encoded JSON string starting at the specified offset. + +## 2. Registry JSON Schema +Root structure: `{"credentials": { ... }}` + +### 2.1 mso_mdoc (credentials.mso_mdoc) +- **Key**: Document Type (e.g., "org.iso.18013.5.1.mDL") +- **Value**: Array of Credential Objects: + - `id`: String. + - `display`: + - `verification`: + - `title`: String. + - `subtitle`: String (optional). + - `explainer`: String (optional). + - `warning`: String (optional). + - `metadata_display_text`: String (optional). + - `icon`: `{"start": , "length": }`. + - `paths`: Map of Namespace -> Map of ClaimName -> Claim object: + - `value`: Any (raw value). + - `display`: + - `verification`: + - `display`: String (localized name). + - `display_value`: String (optional localized value). + +### 2.2 dc+sd-jwt (credentials.dc+sd-jwt) +- **Key**: Verifiable Credential Type (VCT) string. +- **Value**: Array of Credential Objects. +- **Paths Construction**: The Kotlin `SdJwtEntry.claims` (a list) is flattened into a nested `paths` object. Each `SdJwtClaim.path` (an array of strings) defines the nesting. +- **Example**: A claim with `path = ["user", "name", "first"]` becomes: + ```json + "paths": { + "user": { + "name": { + "first": { + "value": "John", + "display": { "verification": { "display": "First Name", ... } } + } + } + } + } + ``` +- **Structure**: + - `id`: String. + - `display`: (same as mso_mdoc). + - `paths`: Recursive nested object. Leaf nodes are Claim objects (same structure as mso_mdoc). + +### 2.3 Issuance (credentials.issuance) +- **mso_mdoc**: Array of MdocInlineIssuanceEntry objects: + - `id`: String. + - `subtitle`: String (optional). + - `title`: String (optional hint). + - `icon`: `{"start": , "length": }` (optional). + - `supported`: Array of DocType Strings. +- **dc+sd-jwt**: Array of SdJwtInlineIssuanceEntry objects: + - `id`: String. + - `subtitle`: String (optional). + - `title`: String (optional hint). + - `icon`: `{"start": , "length": }` (optional). + - `supported`: Array of VCT Strings. + +--- + +## 3. C Function Index + +### base64.c / base64.h +- `static int B64Lookup(char x)`: Helper function that maps Base64-URL characters to their corresponding 6-bit integer values. +- `int B64DecodeURL(char* input, char** output)`: Takes a Base64-URL encoded string and decodes it. It allocates a new buffer for the output using `malloc` and returns the decoded length. It correctly handles base64url specific characters ('-' and '_') as well as standard padding ('='). + +### credentialmanager.c / credentialmanager.h +- Provides ACM (Android Credential Manager) environment bindings to interface with the Android OS. +- `void* GetRequest()`: Fetches the buffer containing the ACM request JSON. +- `void* GetCredentials()`: Fetches the buffer containing the Registry binary blob. +- Also exposes WASM imports for ACM reporting: `AddEntrySet`, `AddEntryToSet`, `AddFieldToEntrySet`, `AddPaymentEntryToSetV2`, `GetWasmVersion`, `AddInlineIssuanceEntry`, etc. + +### dcql.c / dcql.h +- `int AddAllClaims(cJSON* matched_claim_names, cJSON* candidate_paths)`: Recursively traverses a JSON object representing candidate claim paths. For every object containing a "display" key, it adds that "display" object to the `matched_claim_names` array. This is used when a request doesn't specify specific claims, so the matcher must collect all available claims from the credential to show to the user. +- `cJSON* MatchCredential(cJSON* credential, cJSON* credential_store)`: Evaluates a single DCQL `credential` requirement against the registry `credential_store`. + - Determines if the requested format is `mso_mdoc` or `dc+sd-jwt`. + - Checks if the credential candidate matches the `meta` criteria (e.g., matching `doctype_value` for `mso_mdoc`, or `vct_values` for `dc+sd-jwt`). + - Iterates over candidates that matched the `meta` criteria. + - If specific `claims` are requested, it traverses the `paths` of the candidate using the requested JSON paths array. It matches claim values if `values` are specified in the request. + - If `claim_sets` are specified, it verifies that at least one logical group of claims is fully satisfied by the matched claims. + - Identifies matching inline issuance options by comparing `supported` DocTypes or VCTs against the `meta` requirements. + - Returns a JSON object with `matched_creds` (list of matched credentials containing `id`, `display`, `matched_claim_names`, and `matched_claim_metadata`) and an `inline_issuance` entry if applicable. +- `cJSON* dcql_query(cJSON* query, cJSON* credential_store)`: High-level function that orchestrates DCQL evaluation. + - Iterates over all `credentials` in the DCQL query and calls `MatchCredential` for each. + - If `credential_sets` are defined in the query, it iterates over these sets and their options to find valid combinations of matched credentials that satisfy the query logic (handling `required` flags). + - If no `credential_sets` are defined, it requires all requested credentials to match. + - Returns a final `match_result` JSON containing `matched_credential_sets` (valid combinations of credentials) and `matched_credentials` (the actual credential details). + +### openid4vp1_0.c +- `void report_credential_set_length(...)`: Recursively calculates the total number of credentials across all options in a matched credential set and reports this total length to the ACM using `AddEntrySet`. +- `void report_matched_credential(...)`: Reports a specific matched credential to the ACM. + - Constructs a JSON metadata string containing the matched claims, request index, and DCQL IDs. + - Checks if the credential is a payment transaction (if `transaction_credential_ids` match). If so, it reports it as a payment entry via `AddPaymentEntryToSetV2` or `AddPaymentEntryToSet` (depending on the WASM version). + - Otherwise, it reports it as a standard entry via `AddEntryToSet`, providing title, subtitle, explainer, and icon offsets. + - Iterates through `matched_claim_names` to report each individual matched claim via `AddFieldToEntrySet`. + - Reports `metadata_display_text` via `AddMetadataDisplayTextToEntrySet` if present. +- `void report_matched_credential_set(...)`: Recursively iterates through the complex `matched_credential_sets` structure returned by `dcql_query` and calls `report_matched_credential` for each valid credential in each option. +- `int main()`: The global entry point for the WASM module. + - Fetches the credentials binary blob and finds the JSON metadata offset. + - Parses the registry JSON and the DCQL request JSON. + - Determines if the request is OpenID4VP (signed or unsigned) and decodes the payload via `B64DecodeURL` if it's signed (JWS). + - Handles transaction data extraction for payments (merchant name, amount, additional info). + - Calls `dcql_query` to perform the actual matching. + - Extracts the matched results and uses the `report_*` functions to format and send the results back to the Android OS via the ACM API. + - Handles inline issuance fallback by calling `AddInlineIssuanceEntry` if no regular credentials match but inline issuance is supported. + +### testharness.c +- Provides mock implementations for ACM APIs (`GetRequestSize`, `GetRequestBuffer`, `GetCredentialsSize`, `ReadCredentialsBuffer`, etc.) to allow for local execution of the `main()` function. +- Reads test inputs from local files like `request.json` and `testcreds.json`. diff --git a/matcher/openid4vp1_0.c b/matcher/openid4vp1_0.c index 24ab0f8..d21de8d 100644 --- a/matcher/openid4vp1_0.c +++ b/matcher/openid4vp1_0.c @@ -163,7 +163,7 @@ void report_matched_credential(uint32_t wasm_version, cJSON* matched_doc, cJSON* AddFieldForStringIdEntry(id, claim_display, claim_value); } } - if (wasm_version >= 5) { + if (wasm_version >= 5 && metadata_display_text != NULL) { AddMetadataDisplayTextToEntrySet(matched_id, metadata_display_text, set_id, doc_idx); } } @@ -195,7 +195,7 @@ void report_matched_credential_set(char* set_id, int curr_set_idx, cJSON *matche } } -int main() +int openid4vp_main() { uint32_t credentials_size; GetCredentialsSize(&credentials_size); @@ -298,7 +298,7 @@ int main() transaction_data = cJSON_Parse(transaction_data_json); transaction_credential_ids = cJSON_GetObjectItem(transaction_data, "credential_ids"); char *transaction_data_type = cJSON_GetStringValue(cJSON_GetObjectItem(transaction_data, "type")); - if (strcmp(transaction_data_type, "urn:eudi:sca:payment:1") == 0) { + if (transaction_data_type != NULL && strcmp(transaction_data_type, "urn:eudi:sca:payment:1") == 0) { cJSON *payload = cJSON_GetObjectItem(transaction_data, "payload"); merchant_name = cJSON_GetStringValue(cJSON_GetObjectItem(cJSON_GetObjectItem(payload, "payee"), "name")); @@ -316,7 +316,7 @@ int main() printf("transaction amount %s\n", transaction_amount); additional_info = cJSON_GetStringValue(cJSON_GetObjectItem(transaction_data, "additional_info")); - } else if (strcmp(transaction_data_type, "payment_details") == 0) { + } else if (transaction_data_type != NULL && strcmp(transaction_data_type, "payment_details") == 0) { merchant_name = cJSON_GetStringValue(cJSON_GetObjectItem(transaction_data, "payee_name")); char *amount = cJSON_GetStringValue(cJSON_GetObjectItem(transaction_data, "payment_amount")); @@ -347,7 +347,7 @@ int main() cJSON_ArrayForEach(matched_option, first_matched_credential_set) { cJSON *matched_credential_ids = cJSON_GetObjectItemCaseSensitive(matched_option, "matched_credential_ids"); int credential_set_size = cJSON_GetArraySize(matched_credential_ids); - char set_id_buffer[26]; + char set_id_buffer[64]; if (cJSON_HasObjectItem(matched_option, "set_id")) { char *set_idx = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(matched_option, "set_id")); diff --git a/matcher/test_plan.md b/matcher/test_plan.md new file mode 100644 index 0000000..5777a58 --- /dev/null +++ b/matcher/test_plan.md @@ -0,0 +1,339 @@ +# Objective +Add comprehensive unit testing for the C-based OpenID4VP / DCQL matcher in `matcher/`. The tests will cover Base64 decoding, DCQL query execution, credential filtering, and OpenID4VP protocol handling, including Android Credential Manager (ACM) WASM bindings. + +# Proposed Solution +We will design 38 distinct test cases spanning `base64.c`, `dcql.c`, and `openid4vp1_0.c`. The test suite will be written in **C++** using the **`doctest`** testing framework and **`nlohmann/json`** for JSON payload mocking, built via a simple **Makefile** or **CMakeLists.txt**. We are not constrained by Wasm binary size in the test suite. + +## Credential Store Mocking +We will use the following explicit, hardcoded mock registry JSON that covers all permutations tested below. It includes standard `mso_mdoc` credentials, deeply nested `dc+sd-jwt` credentials, issuance fallbacks, and the exact VCT targets needed to execute the complex credential sets from the OpenID4VP DCQL spec example. + +```json +{ + "credentials": { + "mso_mdoc": { + "org.iso.18013.5.1.mDL": [ + { + "id": "mdoc_cred_1", + "display": { + "verification": { + "title": "John's Driving License", + "icon": { "start": 4, "length": 10 } + } + }, + "paths": { + "org.iso.18013.5.1": { + "family_name": { "value": "Doe", "display": { "verification": { "display": "Family Name", "display_value": "Doe" } } }, + "given_name": { "value": "John", "display": { "verification": { "display": "Given Name", "display_value": "John" } } }, + "age": { "value": 21, "display": { "verification": { "display": "Age", "display_value": "Yes" } } }, + "age_over_21": { "value": true, "display": { "verification": { "display": "Over 21" } } } + } + } + }, + { + "id": "mdoc_cred_underage", + "display": { + "verification": { + "title": "Underage License", + "icon": { "start": 4, "length": 10 } + } + }, + "paths": { + "org.iso.18013.5.1": { + "age": { "value": 18, "display": { "verification": { "display": "Age" } } }, + "age_over_21": { "value": false, "display": { "verification": { "display": "Over 21", "display_value": "Yes" } } } + } + } + }, + { + "id": "mdoc_cred_3", + "display": { + "verification": { + "title": "Alice's Driving License", + "icon": { "start": 4, "length": 10 } + } + }, + "paths": { + "org.iso.18013.5.1": { + "family_name": { "value": "Smith", "display": { "verification": { "display": "Family Name" } } }, + "given_name": { "value": "Alice", "display": { "verification": { "display": "Given Name" } } }, + "age": { "value": 25, "display": { "verification": { "display": "Age" } } }, + "age_over_21": { "value": true, "display": { "verification": { "display": "Over 21" } } } + } + } + }, + { + "id": "mdoc_cred_4", + "display": { + "verification": { + "title": "Jane's Driving License", + "icon": { "start": 4, "length": 10 } + } + }, + "paths": { + "org.iso.18013.5.1": { + "family_name": { "value": "Doe", "display": { "verification": { "display": "Family Name" } } }, + "given_name": { "value": "Jane", "display": { "verification": { "display": "Given Name" } } }, + "age": { "value": 30, "display": { "verification": { "display": "Age" } } }, + "age_over_21": { "value": true, "display": { "verification": { "display": "Over 21" } } } + } + } + } + ] + }, + "dc+sd-jwt": { + "urn:eu.europa.ec.eudi:pid:1": [ + { + "id": "sdjwt_cred_1", + "display": { + "verification": { + "title": "My EU PID", + "icon": { "start": 4, "length": 10 } + } + }, + "paths": { + "user": { + "address": { + "locality": { "value": "Brussels", "display": { "verification": { "display": "City" } } }, + "country": { "value": "BE", "display": { "verification": { "display": "Country" } } } + }, + "name": { + "first": { "value": "Jane", "display": { "verification": { "display": "First Name" } } } + } + } + } + } + ], + "https://credentials.example.com/identity_credential": [ + { + "id": "sdjwt_spec_pid", + "display": { "verification": { "title": "Spec PID", "icon": { "start": 4, "length": 10 } } }, + "paths": { + "given_name": { "value": "Alice", "display": { "verification": { "display": "Given Name" } } }, + "family_name": { "value": "Smith", "display": { "verification": { "display": "Family Name" } } }, + "address": { + "street_address": { "value": "123 Spec St", "display": { "verification": { "display": "Street" } } } + } + } + } + ], + "https://othercredentials.example/pid": [ + { + "id": "sdjwt_spec_other_pid", + "display": { "verification": { "title": "Other PID", "icon": { "start": 4, "length": 10 } } }, + "paths": { + "given_name": { "value": "Bob", "display": { "verification": { "display": "Given Name" } } }, + "family_name": { "value": "Jones", "display": { "verification": { "display": "Family Name" } } }, + "address": { + "street_address": { "value": "456 Other St", "display": { "verification": { "display": "Street" } } } + } + } + } + ], + "https://credentials.example.com/reduced_identity_credential": [ + { + "id": "sdjwt_spec_reduced_1", + "display": { "verification": { "title": "Reduced PID", "icon": { "start": 4, "length": 10 } } }, + "paths": { + "given_name": { "value": "Charlie", "display": { "verification": { "display": "Given Name" } } }, + "family_name": { "value": "Brown", "display": { "verification": { "display": "Family Name" } } } + } + } + ], + "https://cred.example/residence_credential": [ + { + "id": "sdjwt_spec_reduced_2", + "display": { "verification": { "title": "Residence Cred", "icon": { "start": 4, "length": 10 } } }, + "paths": { + "postal_code": { "value": "12345", "display": { "verification": { "display": "Zip" } } }, + "locality": { "value": "Townsville", "display": { "verification": { "display": "City" } } }, + "region": { "value": "State", "display": { "verification": { "display": "Region" } } } + } + } + ], + "https://company.example/company_rewards": [ + { + "id": "sdjwt_spec_rewards", + "display": { "verification": { "title": "Rewards", "icon": { "start": 4, "length": 10 } } }, + "paths": { + "rewards_number": { "value": "9999", "display": { "verification": { "display": "Rewards No" } } } + } + } + ] + }, + "issuance": { + "mso_mdoc": [ + { + "id": "issuance_mdl_1", + "title": "Get a New mDL", + "subtitle": "From your local DMV", + "icon": { "start": 4, "length": 10 }, + "supported": [ "org.iso.18013.5.1.mDL" ] + } + ], + "dc+sd-jwt": [ + { + "id": "issuance_pid_1", + "title": "Get a New EU PID", + "subtitle": "Official Digital ID", + "icon": { "start": 4, "length": 10 }, + "supported": [ "urn:eu.europa.ec.eudi:pid:1" ] + } + ] + } + } +} +``` + +*Note: The test suite will construct a raw binary blob containing a mock 4-byte header and icon section prepended to this JSON string.* + +## Fake Credential Manager Design (FakeCredman) +Based on the real Android Credential Manager's host implementation (`RegistryRuntime.kt` and `RegistryRuntimeExt.kt`), the test suite requires a stateful C++ mock to capture WASM import calls. The matcher communicates its results via functions like `AddEntrySet`, `AddEntryToSet`, and `AddFieldToEntrySet`. + +The `FakeCredman` will be a global singleton tracking these invocations: +- **Data Structures**: + - `EntryType`: Enum (`Verification`, `InlineIssuance`, `Payment`, `UserInfo`, `Export`) to distinguish between the types of entries added by the matcher. + - `FakeEntry`: Struct storing `credId`, `type` (of `EntryType`), `title`, `subtitle`, `disclaimer`, `warning`, `metadata_display_text`, a vector of `fields` (key-value pairs), and payment details (`merchant_name`, `transaction_amount`). + - `FakeEntrySet`: Struct storing `setId`, `setLength`, and a nested map `std::map> entries` (keyed by `setIndex` and `credId`). + - `FakeStandaloneEntries`: For entries not in a set (e.g., `AddInlineIssuanceEntry`). +- **Mocks**: It will export `extern "C"` functions mimicking the host bindings, routing arguments into the `FakeCredman` state and assigning the appropriate `EntryType`: + - `AddEntrySet(setId, setLength)` + - `AddEntryToSet(...)` -> Creates `FakeEntry` with `type = Verification`. + - `AddFieldToEntrySet(...)` -> Appends to `fields` of the matching entry. + - `AddPaymentEntryToSetV2(...)` -> Creates `FakeEntry` with `type = Payment`. + - `AddMetadataDisplayTextToEntrySet(...)` -> Updates `metadata_display_text`. + - `AddInlineIssuanceEntry(...)` -> Creates `FakeEntry` in `FakeStandaloneEntries` with `type = InlineIssuance`. +- **Verification**: Tests will reset `FakeCredman` before each run and assert on its final state (e.g., verifying `FakeCredman::GetInstance().entrySets["my_set"].entries[0]["cred_123"].type == Verification`). + +## Test Cases & Assertions + +For every test case that executes a matcher query, we will assert not only the internal C structures (e.g., `matched_creds`) but also the exact state pushed to the `FakeCredman` about the added entry set (ID), the entries contained in each set, and their correct `EntryType`. + +### Group 1: Base64-URL Decoding (`base64.c`) +1. **TC01_DecodeEmptyString**: Input `""`. Assert output length is 0, buffer is empty. +2. **TC02_DecodeNoPadding**: Input `"SGVsbG8"`. Assert output length is 5, buffer matches `"Hello"`. +3. **TC03_DecodeOnePadding**: Input `"SGVsbG8="`. Assert output length is 5. +4. **TC04_DecodeTwoPaddings**: Input `"SGVsbA=="`. Assert output length is 4. +5. **TC05_DecodeUrlSafeChars**: Input `"-_-_"`. Assert output length is 3, buffer matches raw binary conversion. +6. **TC06_DecodeInvalidChars**: Input `"SGV@#G8"`. Assert function handles gracefully (outputs mapped zeros based on `B64Lookup`). + +### Group 2: DCQL Query & Matching (`dcql.c`) +7. **TC07_MdocMatch**: Request `mso_mdoc` with `doctype_value: org.iso.mDL`. Assert `MatchCredential` returns candidate in `matched_creds`. Assert `FakeCredman` receives `AddEntrySet` and `AddEntryToSet` with the expected `credId` and `type = Verification`. +8. **TC08_MdocMismatch**: Request `mso_mdoc` with `doctype_value: UNKNOWN`. Assert `matched_creds` is empty. Assert `FakeCredman.entrySets` is empty. +9. **TC09_SdjwtMatch**: Request `dc+sd-jwt` with `vct_values: ["urn:eu.europa.ec.eudi:pid:1"]`. Assert candidate match. Assert `FakeCredman` registers the `dc+sd-jwt` entry in the expected set index with `type = Verification`. +10. **TC10_SdjwtMismatch**: Request `dc+sd-jwt` with `vct_values: ["UNKNOWN"]`. Assert `matched_creds` is empty. +11. **TC11_InlineIssuanceFallback**: Request `mso_mdoc` where credentials don't match, but `issuance` list has matching supported doctype. Assert `FakeCredman` receives `AddInlineIssuanceEntry`, creating an entry with `type = InlineIssuance`, correct `title`/`subtitle`, and empty `fields`. +12. **TC12_MissingFormat**: Request `w3c_vc`. Store has no `w3c_vc` candidates. Assert `matched_creds` is empty. +13. **TC13_ReturnAllClaims**: Query has no `claims` array. Assert `AddAllClaims` populates `matched_claim_names`. Assert `FakeCredman` receives `AddFieldToEntrySet` for *all* candidate claims on the Verification entry. +14. **TC14_MatchSpecificClaims**: Query asks for `["family_name"]`. Assert `FakeCredman` receives exactly 1 `AddFieldToEntrySet` call for "Family Name". +15. **TC15_MatchNestedClaims**: Query asks for path `["address", "locality"]`. Assert deep traversal resolves the claim and pushes it to `FakeCredman`. +16. **TC16_FailMissingClaims**: Query asks for path `["unknown", "claim"]`. Assert credential does not append to `matched_creds`. +17. **TC17_MatchClaimValuesBool**: Query specifies claim `age_over_21` with `values: [true]`. Candidate has boolean `true`. Assert `FakeCredman` registers the entry. +18. **TC18_FailClaimValuesBool**: Query specifies claim `age_over_21` with `values: [true]`. Candidate has boolean `false`. Assert `FakeCredman.entrySets` is empty. +19. **TC19_MatchClaimValuesInt**: Query specifies integer claim `age` with `values: [21, 22]`. Candidate has integer `21`. Assert `FakeCredman` registers the entry. +20. **TC20_FailClaimValuesInt**: Query specifies integer claim `age` with `values: [21, 22]`. Candidate has integer `18`. Assert `FakeCredman.entrySets` is empty. +21. **TC21_MatchFirstClaimSet**: Query specifies two `claim_sets`. Candidate satisfies set 1. Assert `FakeCredman` registers the entry. +22. **TC22_MatchSecondClaimSet**: Candidate lacks claims for set 1, but satisfies set 2. Assert `FakeCredman` registers the entry. +23. **TC23_FailAllClaimSets**: Candidate satisfies neither claim set. Assert mismatch. +24. **TC24_DcqlQuerySingle**: Run `dcql_query` with one required credential. Assert `FakeCredman` populates `entrySets["request_id_0"]` with `setLength=1`. +25. **TC25_DcqlQuerySetMatch**: `dcql_query` with `credential_sets` where `required: true` set is matched. Assert `FakeCredman` registers the matched Verification entries under the correctly assigned `setId`. +26. **TC26_DcqlQuerySetFailRequired**: `credential_sets` where `required: true` set fails. Assert `FakeCredman` remains empty. +27. **TC27_DcqlQuerySetFailOptional**: `credential_sets` where `required: false` set fails, but `required: true` matches. Assert overall match succeeds in `FakeCredman`. +28. **TC28_DcqlQueryComplexOverlappingSets**: Execute a `dcql_query` using `credential_sets` that define 3 options/sets, where each option requires at least 2 credentials. Design the mock credentials such that the same `credId` fulfills requirements across multiple sets. Assert `FakeCredman` populates 3 distinct entry sets (i.e. length of `entrySets` is 3), each containing at least 2 entries, and verify that the overlapping `credId` (like `mdoc_cred_4`) is correctly registered in the overlapping sets without errors. +29. **TC29_DcqlQueryOpenID4VPSpecExample**: Execute the specific DCQL query from the OpenID4VP spec (detailed below) containing multiple `dc+sd-jwt` requests and complex `credential_sets` (Required Set: `[pid]`, `[other_pid]`, `[pid_reduced_cred_1, pid_reduced_cred_2]`; Optional Set: `[nice_to_have]`). Assert `FakeCredman` successfully processes the combinations and populates the expected discrete entry sets matching the registry data. + +```json +{ + "credentials": [ + { + "id": "pid", + "format": "dc+sd-jwt", + "meta": { + "vct_values": ["https://credentials.example.com/identity_credential"] + }, + "claims": [ + {"path": ["given_name"]}, + {"path": ["family_name"]}, + {"path": ["address", "street_address"]} + ] + }, + { + "id": "other_pid", + "format": "dc+sd-jwt", + "meta": { + "vct_values": ["https://othercredentials.example/pid"] + }, + "claims": [ + {"path": ["given_name"]}, + {"path": ["family_name"]}, + {"path": ["address", "street_address"]} + ] + }, + { + "id": "pid_reduced_cred_1", + "format": "dc+sd-jwt", + "meta": { + "vct_values": ["https://credentials.example.com/reduced_identity_credential"] + }, + "claims": [ + {"path": ["family_name"]}, + {"path": ["given_name"]} + ] + }, + { + "id": "pid_reduced_cred_2", + "format": "dc+sd-jwt", + "meta": { + "vct_values": ["https://cred.example/residence_credential"] + }, + "claims": [ + {"path": ["postal_code"]}, + {"path": ["locality"]}, + {"path": ["region"]} + ] + }, + { + "id": "nice_to_have", + "format": "dc+sd-jwt", + "meta": { + "vct_values": ["https://company.example/company_rewards"] + }, + "claims": [ + {"path": ["rewards_number"]} + ] + } + ], + "credential_sets": [ + { + "options": [ + [ "pid" ], + [ "other_pid" ], + [ "pid_reduced_cred_1", "pid_reduced_cred_2" ] + ] + }, + { + "required": false, + "options": [ + [ "nice_to_have" ] + ] + } + ] +} +``` + +### Group 3: Protocol Parsing & Integration (`openid4vp1_0.c` & ACM bindings) +30. **TC30_ParseV1Unsigned**: Mock `dc_request` with `openid4vp-v1-unsigned`. Assert JSON payload parsed correctly. +31. **TC31_ParseV1Signed**: Mock `dc_request` with `openid4vp-v1-signed` (JWS). Assert payload extracted, split by '.', and Base64-decoded into JSON. +32. **TC32_ExtractPaymentSca1**: Mock `transaction_data` type `urn:eudi:sca:payment:1`. Assert `FakeCredman` receives `AddPaymentEntryToSetV2`, creating an entry with `type = Payment`, `merchant_name` from `payload.payee.name` and correctly calculated amount. +33. **TC33_ExtractPaymentDetails**: Mock `transaction_data` type `payment_details`. Assert `FakeCredman` Payment entry receives amount concatenated with currency. +34. **TC34_ExtractPaymentGeneric**: Mock `transaction_data` lacking type. Assert fallback to `merchant_name` and `amount` keys on the Payment entry in `FakeCredman`. +35. **TC35_WasmAddEntryToSet**: Mock WASM version 2 (non-payment). Assert `AddEntryToSet` invoked. Assert `FakeCredman` captures correct title, subtitle, and icon offset/len with `type = Verification`. +36. **TC36_WasmPaymentV2**: Mock WASM version 3 (payment). Assert `FakeCredman` verifies `AddPaymentEntryToSetV2` created a `Payment` entry and parsed transaction amount/merchant accurately. +37. **TC37_WasmPaymentV1**: Mock WASM version 2 (payment). Assert `FakeCredman` receives `AddPaymentEntryToSet` (legacy) instead of V2, creating a `Payment` entry. +38. **TC38_WasmMetadataText**: Mock WASM version 5. Assert `FakeCredman` receives `AddMetadataDisplayTextToEntrySet` appending the expected `metadata_display_text` string to the correct Verification entry. + +# Implementation Plan +1. **Mock Setup**: Instantiate the explicit `cJSON` or `nlohmann/json` string payload from the plan inside `test_runner.cc`. +2. **Fake Credman**: Implement the `FakeCredman` global state (including `EntryType` distinguishing logic) and the `extern "C"` functions mimicking `RegistryRuntime.kt` (e.g. `AddEntrySet`, `AddEntryToSet`, `AddFieldToEntrySet`). +3. **Framework & Build**: Create a `Makefile` or `CMakeLists.txt` using the system-installed `doctest.h` and `nlohmann/json.hpp`. +4. **C++ Interop**: Write `test_runner.cc`, including the C headers (`extern "C"`) and linking the mock APIs so `openid4vp1_0.c` and `dcql.c` execute correctly. +5. **Tests Implementation**: Implement `TEST_CASE` blocks in `test_runner.cc` covering TC01 through TC38. Ensure every matcher test asserts `FakeCredman` state (e.g., set IDs, entry counts, `EntryType`, field names, and values). \ No newline at end of file diff --git a/matcher/test_runner.cc b/matcher/test_runner.cc new file mode 100644 index 0000000..1811827 --- /dev/null +++ b/matcher/test_runner.cc @@ -0,0 +1,438 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "cJSON/cJSON.h" +#include "dcql.h" +#include "base64.h" +#include "credentialmanager.h" +int openid4vp_main(); +} + +using json = nlohmann::json; + +// --- FakeCredman Implementation --- +enum class EntryType { + Verification, + InlineIssuance, + Payment, + UserInfo, + Export +}; + +NLOHMANN_JSON_SERIALIZE_ENUM(EntryType, { + {EntryType::Verification, "Verification"}, + {EntryType::InlineIssuance, "InlineIssuance"}, + {EntryType::Payment, "Payment"}, + {EntryType::UserInfo, "UserInfo"}, + {EntryType::Export, "Export"} +}) + +struct FakeEntry { + std::string credId; + EntryType type; + std::string title; + std::string subtitle; + std::string disclaimer; + std::string warning; + std::string metadata_display_text; + std::vector> fields; + std::string merchant_name; + std::string transaction_amount; + std::string additional_info; +}; + +void to_json(json& j, const FakeEntry& e) { + j = json{ + {"credId", e.credId}, + {"type", e.type}, + {"title", e.title}, + {"subtitle", e.subtitle}, + {"disclaimer", e.disclaimer}, + {"warning", e.warning}, + {"metadata_display_text", e.metadata_display_text}, + {"fields", e.fields}, + {"merchant_name", e.merchant_name}, + {"transaction_amount", e.transaction_amount}, + {"additional_info", e.additional_info} + }; +} + +struct FakeEntrySet { + std::string setId; + int setLength; + // setIndex -> credId -> entry + std::map> entries; +}; + +void to_json(json& j, const FakeEntrySet& s) { + j = json{ + {"setId", s.setId}, + {"setLength", s.setLength}, + {"entries", s.entries} + }; +} + +class FakeCredman { +public: + static FakeCredman& GetInstance() { + static FakeCredman instance; + return instance; + } + + void Reset() { + entrySets.clear(); + standaloneEntries.clear(); + wasmVersion = 9999; + requestJson = ""; + credentialsBlob.clear(); + } + + std::map entrySets; + std::vector standaloneEntries; + uint32_t wasmVersion = 9999; + std::string requestJson; + std::vector credentialsBlob; + +private: + FakeCredman() = default; +}; + +void to_json(json& j, const FakeCredman& c) { + j = json{ + {"entrySets", c.entrySets}, + {"standaloneEntries", c.standaloneEntries} + }; +} + +std::string ReadFileToString(const std::string& path) { + std::ifstream t(path); + if (!t.is_open()) return ""; + std::string str((std::istreambuf_iterator(t)), + std::istreambuf_iterator()); + return str; +} + +void WriteStringToFile(const std::string& path, const std::string& content) { + std::ofstream out(path); + out << content; +} + +// --- Mocked ACM APIs (extern "C") --- +extern "C" { +void GetWasmVersion(uint32_t* version) { + *version = FakeCredman::GetInstance().wasmVersion; +} + +void GetRequestSize(uint32_t* size) { + *size = FakeCredman::GetInstance().requestJson.size(); +} + +void GetRequestBuffer(void* buffer) { + memcpy(buffer, FakeCredman::GetInstance().requestJson.c_str(), FakeCredman::GetInstance().requestJson.size()); +} + +void GetCredentialsSize(uint32_t* size) { + *size = FakeCredman::GetInstance().credentialsBlob.size(); +} + +size_t ReadCredentialsBuffer(void* buffer, size_t offset, size_t len) { + if (offset >= FakeCredman::GetInstance().credentialsBlob.size()) return 0; + size_t toRead = std::min(len, (size_t)(FakeCredman::GetInstance().credentialsBlob.size() - offset)); + memcpy(buffer, FakeCredman::GetInstance().credentialsBlob.data() + offset, toRead); + return toRead; +} + +void AddEntrySet(const char* set_id, int set_length) { + std::string s_id = set_id ? set_id : ""; + FakeCredman::GetInstance().entrySets[s_id] = {s_id, set_length, {}}; +} + +void AddEntryToSet(const char* cred_id, const char* /*icon*/, size_t /*icon_len*/, const char* title, const char* subtitle, const char* disclaimer, const char* warning, const char* /*metadata*/, const char* set_id, int set_index) { + FakeEntry entry; + entry.credId = cred_id ? cred_id : ""; + entry.type = EntryType::Verification; + entry.title = title ? title : ""; + entry.subtitle = subtitle ? subtitle : ""; + entry.disclaimer = disclaimer ? disclaimer : ""; + entry.warning = warning ? warning : ""; + std::string s_id = set_id ? set_id : ""; + FakeCredman::GetInstance().entrySets[s_id].entries[std::to_string(set_index)][entry.credId] = entry; +} + +void AddFieldToEntrySet(const char* cred_id, const char* field_display_name, const char* field_display_value, const char* set_id, int set_index) { + std::string c_id = cred_id ? cred_id : ""; + std::string f_name = field_display_name ? field_display_name : ""; + std::string f_val = field_display_value ? field_display_value : ""; + std::string s_id = set_id ? set_id : ""; + FakeCredman::GetInstance().entrySets[s_id].entries[std::to_string(set_index)][c_id].fields.push_back({f_name, f_val}); +} + +void AddPaymentEntryToSetV2(const char* cred_id, const char* merchant_name, const char* /*payment_method_name*/, const char* /*payment_method_subtitle*/, const char* /*payment_method_icon*/, size_t /*payment_method_icon_len*/, const char* transaction_amount, const char* /*bank_icon*/, size_t /*bank_icon_len*/, const char* /*payment_provider_icon*/, size_t /*payment_provider_icon_len*/, const char* additional_info, const char* /*metadata*/, const char* set_id, int set_index) { + FakeEntry entry; + entry.credId = cred_id ? cred_id : ""; + entry.type = EntryType::Payment; + entry.merchant_name = merchant_name ? merchant_name : ""; + entry.transaction_amount = transaction_amount ? transaction_amount : ""; + entry.additional_info = additional_info ? additional_info : ""; + std::string s_id = set_id ? set_id : ""; + FakeCredman::GetInstance().entrySets[s_id].entries[std::to_string(set_index)][entry.credId] = entry; +} + +void AddPaymentEntryToSet(const char* cred_id, const char* merchant_name, const char* payment_method_name, const char* payment_method_subtitle, const char* payment_method_icon, size_t payment_method_icon_len, const char* transaction_amount, const char* bank_icon, size_t bank_icon_len, const char* payment_provider_icon, size_t payment_provider_icon_len, const char* metadata, const char* set_id, int set_index) { + AddPaymentEntryToSetV2(cred_id, merchant_name, payment_method_name, payment_method_subtitle, payment_method_icon, payment_method_icon_len, transaction_amount, bank_icon, bank_icon_len, payment_provider_icon, payment_provider_icon_len, "", metadata, set_id, set_index); +} + +void AddMetadataDisplayTextToEntrySet(const char *cred_id, const char *metadata_display_text, const char *set_id, int set_index) { + std::string c_id = cred_id ? cred_id : ""; + std::string m_text = metadata_display_text ? metadata_display_text : ""; + std::string s_id = set_id ? set_id : ""; + FakeCredman::GetInstance().entrySets[s_id].entries[std::to_string(set_index)][c_id].metadata_display_text = m_text; +} + +void AddInlineIssuanceEntry(const char* cred_id, const char* /*icon*/, size_t /*icon_len*/, const char* title, const char* subtitle) { + FakeEntry entry; + entry.credId = cred_id ? cred_id : ""; + entry.type = EntryType::InlineIssuance; + entry.title = title ? title : ""; + entry.subtitle = subtitle ? subtitle : ""; + FakeCredman::GetInstance().standaloneEntries.push_back(entry); +} + +// Deprecated or unused stubs +void AddEntry(long long, const char*, size_t, const char*, const char*, const char*, const char*) {} +void AddField(long long, const char*, const char*) {} +void AddStringIdEntry(const char*, const char*, size_t, const char*, const char*, const char*, const char*) {} +void AddFieldForStringIdEntry(const char*, const char*, const char*) {} +void AddPaymentEntry(const char*, const char*, const char*, const char*, const char*, size_t, const char*, const char*, size_t, const char*, size_t) {} +void SetAdditionalDisclaimerAndUrlForVerificationEntry(const char*, const char*, const char*, const char*) {} +void SetAdditionalDisclaimerAndUrlForVerificationEntryInCredentialSet(const char*, const char*, const char*, const char*, const char*, int) {} +void GetCallingAppInfo(CallingAppInfo*) {} +void SelfDeclarePackageInfo(const char*, const char*, size_t) {} +} + +// --- Helper for creating registry blob --- +std::vector CreateRegistryBlob(const std::string& jsonStr) { + std::vector blob; + int offset = 4 + 10; // 4 bytes header + 10 bytes mock icon + blob.resize(offset + jsonStr.size()); + memcpy(blob.data(), &offset, 4); + for (int i = 0; i < 10; ++i) blob[4 + i] = (uint8_t)i; + memcpy(blob.data() + offset, jsonStr.c_str(), jsonStr.size()); + return blob; +} + +void RunTest(const std::string& test_name, const std::string& custom_registry = "") { + FakeCredman::GetInstance().Reset(); + std::string registry_json_str = custom_registry.empty() ? ReadFileToString("testdata/registry.json") : custom_registry; + FakeCredman::GetInstance().credentialsBlob = CreateRegistryBlob(registry_json_str); + + std::string loaded_request = ReadFileToString("testdata/" + test_name + "_request.json"); + // Ensure we parse and dump to normalize, or just use it directly. The original code used dump() + FakeCredman::GetInstance().requestJson = json::parse(loaded_request).dump(); + + const char* generate_env = std::getenv("GENERATE_TESTDATA"); + bool generate = generate_env && std::string(generate_env) == "1"; + + openid4vp_main(); + + json result_json = FakeCredman::GetInstance(); + if (generate) { + WriteStringToFile("testdata/" + test_name + "_expected.json", result_json.dump(2)); + } else { + std::string loaded_expected = ReadFileToString("testdata/" + test_name + "_expected.json"); + CHECK(json::parse(loaded_expected) == result_json); + } +} + + + +// --- Group 1: Base64-URL Decoding --- +TEST_CASE("TC01_DecodeEmptyString") { + char* output = nullptr; + int len = B64DecodeURL((char*)"", &output); + CHECK(len == 0); + if (output) free(output); +} + +TEST_CASE("TC02_DecodeNoPadding") { + char* output = nullptr; + int len = B64DecodeURL((char*)"SGVsbG8", &output); + CHECK(len == 5); + CHECK(std::string(output, len) == "Hello"); + if (output) free(output); +} + +TEST_CASE("TC03_DecodeOnePadding") { + char* output = nullptr; + int len = B64DecodeURL((char*)"SGVsbG8=", &output); + CHECK(len == 5); + CHECK(std::string(output, len) == "Hello"); + if (output) free(output); +} + +TEST_CASE("TC04_DecodeTwoPaddings") { + char* output = nullptr; + int len = B64DecodeURL((char*)"SGVsbA==", &output); + CHECK(len == 4); + CHECK(std::string(output, len) == "Hell"); + if (output) free(output); +} + +TEST_CASE("TC05_DecodeUrlSafeChars") { + char* output = nullptr; + int len = B64DecodeURL((char*)"-_-_", &output); + CHECK(len == 3); + CHECK((uint8_t)output[0] == 0xFB); + CHECK((uint8_t)output[1] == 0xFF); + CHECK((uint8_t)output[2] == 0xBF); + if (output) free(output); +} + +TEST_CASE("TC06_DecodeInvalidChars") { + char* output = nullptr; + B64DecodeURL((char*)"SGV@#G8", &output); + if (output) free(output); +} + +// --- Group 2: DCQL Query & Matching --- +TEST_CASE("TC07_MdocMatch") { + RunTest("TC07_MdocMatch"); +} + +TEST_CASE("TC08_MdocMismatch") { + RunTest("TC08_MdocMismatch"); +} + +TEST_CASE("TC09_SdjwtMatch") { + RunTest("TC09_SdjwtMatch"); +} + +TEST_CASE("TC10_SdjwtMismatch") { + RunTest("TC10_SdjwtMismatch"); +} + +TEST_CASE("TC11_InlineIssuanceFallback") { + RunTest("TC11_InlineIssuanceFallback"); +} + +TEST_CASE("TC12_MissingFormat") { + RunTest("TC12_MissingFormat"); +} + +TEST_CASE("TC13_ReturnAllClaims") { + RunTest("TC13_ReturnAllClaims"); +} + +TEST_CASE("TC14_MatchSpecificClaims") { + RunTest("TC14_MatchSpecificClaims"); +} + +TEST_CASE("TC15_MatchNestedClaims") { + RunTest("TC15_MatchNestedClaims"); +} + +TEST_CASE("TC16_FailMissingClaims") { + RunTest("TC16_FailMissingClaims"); +} + +TEST_CASE("TC17_MatchClaimValuesBool") { + RunTest("TC17_MatchClaimValuesBool"); +} + +TEST_CASE("TC18_FailClaimValuesBool") { + RunTest("TC18_FailClaimValuesBool"); +} + +TEST_CASE("TC19_MatchClaimValuesInt") { + RunTest("TC19_MatchClaimValuesInt"); +} + +TEST_CASE("TC20_FailClaimValuesInt") { + RunTest("TC20_FailClaimValuesInt"); +} + +TEST_CASE("TC21_MatchFirstClaimSet") { + RunTest("TC21_MatchFirstClaimSet"); +} + +TEST_CASE("TC22_MatchSecondClaimSet") { + RunTest("TC22_MatchSecondClaimSet"); +} + +TEST_CASE("TC23_FailAllClaimSets") { + RunTest("TC23_FailAllClaimSets"); +} + +TEST_CASE("TC24_DcqlQuerySingle") { + RunTest("TC24_DcqlQuerySingle"); +} + +TEST_CASE("TC25_DcqlQuerySetMatch") { + RunTest("TC25_DcqlQuerySetMatch"); +} + +TEST_CASE("TC26_DcqlQuerySetFailRequired") { + RunTest("TC26_DcqlQuerySetFailRequired"); +} + +TEST_CASE("TC27_DcqlQuerySetFailOptional") { + RunTest("TC27_DcqlQuerySetFailOptional"); +} + +TEST_CASE("TC28_DcqlQueryComplexOverlappingSets") { + RunTest("TC28_DcqlQueryComplexOverlappingSets"); +} + +TEST_CASE("TC29_DcqlQueryOpenID4VPSpecExample") { + RunTest("TC29_DcqlQueryOpenID4VPSpecExample"); +} + +// --- Group 3: Protocol Parsing & Integration --- +TEST_CASE("TC30_ParseV1Unsigned") { + RunTest("TC30_ParseV1Unsigned"); +} + +TEST_CASE("TC31_ParseV1Signed") { + RunTest("TC31_ParseV1Signed"); +} + +TEST_CASE("TC32_ExtractPaymentSca1") { + RunTest("TC32_ExtractPaymentSca1"); +} + +TEST_CASE("TC33_ExtractPaymentDetails") { + RunTest("TC33_ExtractPaymentDetails"); +} + +TEST_CASE("TC34_ExtractPaymentGeneric") { + RunTest("TC34_ExtractPaymentGeneric"); +} + +TEST_CASE("TC35_WasmAddEntryToSet") { + RunTest("TC35_WasmAddEntryToSet"); +} + +TEST_CASE("TC36_WasmPaymentV2") { + RunTest("TC36_WasmPaymentV2"); +} + +TEST_CASE("TC37_WasmMetadataText") { + std::string registry_with_meta = ReadFileToString("testdata/registry.json"); + size_t pos = registry_with_meta.find("\"title\": \"John's Driving License\""); + if (pos != std::string::npos) { + registry_with_meta.insert(pos, "\"metadata_display_text\": \"Verified Member\", "); + } + + RunTest("TC37_WasmMetadataText", registry_with_meta); +} \ No newline at end of file diff --git a/matcher/testdata/TC07_MdocMatch_expected.json b/matcher/testdata/TC07_MdocMatch_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC07_MdocMatch_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC07_MdocMatch_request.json b/matcher/testdata/TC07_MdocMatch_request.json new file mode 100644 index 0000000..90ba703 --- /dev/null +++ b/matcher/testdata/TC07_MdocMatch_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC08_MdocMismatch_expected.json b/matcher/testdata/TC08_MdocMismatch_expected.json new file mode 100644 index 0000000..abaa848 --- /dev/null +++ b/matcher/testdata/TC08_MdocMismatch_expected.json @@ -0,0 +1,4 @@ +{ + "entrySets": {}, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC08_MdocMismatch_request.json b/matcher/testdata/TC08_MdocMismatch_request.json new file mode 100644 index 0000000..0943874 --- /dev/null +++ b/matcher/testdata/TC08_MdocMismatch_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "UNKNOWN" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC09_SdjwtMatch_expected.json b/matcher/testdata/TC09_SdjwtMatch_expected.json new file mode 100644 index 0000000..3b821bc --- /dev/null +++ b/matcher/testdata/TC09_SdjwtMatch_expected.json @@ -0,0 +1,53 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "sdjwt_cred_1": { + "additional_info": "", + "credId": "sdjwt_cred_1", + "disclaimer": "", + "fields": [ + [ + "City", + "Brussels" + ], + [ + "Country", + "Belgium" + ], + [ + "First Name", + "Jane" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "My EU PID", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_pid_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "Official Digital ID", + "title": "Get a New EU PID", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC09_SdjwtMatch_request.json b/matcher/testdata/TC09_SdjwtMatch_request.json new file mode 100644 index 0000000..f7c8499 --- /dev/null +++ b/matcher/testdata/TC09_SdjwtMatch_request.json @@ -0,0 +1,22 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "urn:eu.europa.ec.eudi:pid:1" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC10_SdjwtMismatch_expected.json b/matcher/testdata/TC10_SdjwtMismatch_expected.json new file mode 100644 index 0000000..abaa848 --- /dev/null +++ b/matcher/testdata/TC10_SdjwtMismatch_expected.json @@ -0,0 +1,4 @@ +{ + "entrySets": {}, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC10_SdjwtMismatch_request.json b/matcher/testdata/TC10_SdjwtMismatch_request.json new file mode 100644 index 0000000..6b61601 --- /dev/null +++ b/matcher/testdata/TC10_SdjwtMismatch_request.json @@ -0,0 +1,22 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "UNKNOWN" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC11_InlineIssuanceFallback_expected.json b/matcher/testdata/TC11_InlineIssuanceFallback_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC11_InlineIssuanceFallback_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC11_InlineIssuanceFallback_request.json b/matcher/testdata/TC11_InlineIssuanceFallback_request.json new file mode 100644 index 0000000..14ff033 --- /dev/null +++ b/matcher/testdata/TC11_InlineIssuanceFallback_request.json @@ -0,0 +1,21 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ], + "offer": true + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC12_MissingFormat_expected.json b/matcher/testdata/TC12_MissingFormat_expected.json new file mode 100644 index 0000000..abaa848 --- /dev/null +++ b/matcher/testdata/TC12_MissingFormat_expected.json @@ -0,0 +1,4 @@ +{ + "entrySets": {}, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC12_MissingFormat_request.json b/matcher/testdata/TC12_MissingFormat_request.json new file mode 100644 index 0000000..3fd4079 --- /dev/null +++ b/matcher/testdata/TC12_MissingFormat_request.json @@ -0,0 +1,22 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "w3c_vc", + "id": "w3c", + "meta": { + "vct_values": [ + "some_vct" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC13_ReturnAllClaims_expected.json b/matcher/testdata/TC13_ReturnAllClaims_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC13_ReturnAllClaims_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC13_ReturnAllClaims_request.json b/matcher/testdata/TC13_ReturnAllClaims_request.json new file mode 100644 index 0000000..90ba703 --- /dev/null +++ b/matcher/testdata/TC13_ReturnAllClaims_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC14_MatchSpecificClaims_expected.json b/matcher/testdata/TC14_MatchSpecificClaims_expected.json new file mode 100644 index 0000000..f00ee4c --- /dev/null +++ b/matcher/testdata/TC14_MatchSpecificClaims_expected.json @@ -0,0 +1,81 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC14_MatchSpecificClaims_request.json b/matcher/testdata/TC14_MatchSpecificClaims_request.json new file mode 100644 index 0000000..fa7efee --- /dev/null +++ b/matcher/testdata/TC14_MatchSpecificClaims_request.json @@ -0,0 +1,28 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "family_name" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC15_MatchNestedClaims_expected.json b/matcher/testdata/TC15_MatchNestedClaims_expected.json new file mode 100644 index 0000000..b37de1d --- /dev/null +++ b/matcher/testdata/TC15_MatchNestedClaims_expected.json @@ -0,0 +1,45 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "sdjwt_cred_1": { + "additional_info": "", + "credId": "sdjwt_cred_1", + "disclaimer": "", + "fields": [ + [ + "City", + "Brussels" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "My EU PID", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_pid_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "Official Digital ID", + "title": "Get a New EU PID", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC15_MatchNestedClaims_request.json b/matcher/testdata/TC15_MatchNestedClaims_request.json new file mode 100644 index 0000000..8b048cf --- /dev/null +++ b/matcher/testdata/TC15_MatchNestedClaims_request.json @@ -0,0 +1,31 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "user", + "address", + "locality" + ] + } + ], + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "urn:eu.europa.ec.eudi:pid:1" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC16_FailMissingClaims_expected.json b/matcher/testdata/TC16_FailMissingClaims_expected.json new file mode 100644 index 0000000..1795300 --- /dev/null +++ b/matcher/testdata/TC16_FailMissingClaims_expected.json @@ -0,0 +1,18 @@ +{ + "entrySets": {}, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_pid_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "Official Digital ID", + "title": "Get a New EU PID", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC16_FailMissingClaims_request.json b/matcher/testdata/TC16_FailMissingClaims_request.json new file mode 100644 index 0000000..c5d9f30 --- /dev/null +++ b/matcher/testdata/TC16_FailMissingClaims_request.json @@ -0,0 +1,30 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "unknown", + "claim" + ] + } + ], + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "urn:eu.europa.ec.eudi:pid:1" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC17_MatchClaimValuesBool_expected.json b/matcher/testdata/TC17_MatchClaimValuesBool_expected.json new file mode 100644 index 0000000..59ad20a --- /dev/null +++ b/matcher/testdata/TC17_MatchClaimValuesBool_expected.json @@ -0,0 +1,81 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC17_MatchClaimValuesBool_request.json b/matcher/testdata/TC17_MatchClaimValuesBool_request.json new file mode 100644 index 0000000..1b124fa --- /dev/null +++ b/matcher/testdata/TC17_MatchClaimValuesBool_request.json @@ -0,0 +1,31 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "age_over_21" + ], + "values": [ + true + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC18_FailClaimValuesBool_expected.json b/matcher/testdata/TC18_FailClaimValuesBool_expected.json new file mode 100644 index 0000000..b4a18e6 --- /dev/null +++ b/matcher/testdata/TC18_FailClaimValuesBool_expected.json @@ -0,0 +1,45 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC18_FailClaimValuesBool_request.json b/matcher/testdata/TC18_FailClaimValuesBool_request.json new file mode 100644 index 0000000..645373e --- /dev/null +++ b/matcher/testdata/TC18_FailClaimValuesBool_request.json @@ -0,0 +1,31 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "age_over_21" + ], + "values": [ + false + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC19_MatchClaimValuesInt_expected.json b/matcher/testdata/TC19_MatchClaimValuesInt_expected.json new file mode 100644 index 0000000..0239900 --- /dev/null +++ b/matcher/testdata/TC19_MatchClaimValuesInt_expected.json @@ -0,0 +1,45 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC19_MatchClaimValuesInt_request.json b/matcher/testdata/TC19_MatchClaimValuesInt_request.json new file mode 100644 index 0000000..5a50dd0 --- /dev/null +++ b/matcher/testdata/TC19_MatchClaimValuesInt_request.json @@ -0,0 +1,32 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "age" + ], + "values": [ + 21, + 22 + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC20_FailClaimValuesInt_expected.json b/matcher/testdata/TC20_FailClaimValuesInt_expected.json new file mode 100644 index 0000000..5db3910 --- /dev/null +++ b/matcher/testdata/TC20_FailClaimValuesInt_expected.json @@ -0,0 +1,18 @@ +{ + "entrySets": {}, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC20_FailClaimValuesInt_request.json b/matcher/testdata/TC20_FailClaimValuesInt_request.json new file mode 100644 index 0000000..355412f --- /dev/null +++ b/matcher/testdata/TC20_FailClaimValuesInt_request.json @@ -0,0 +1,31 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "age" + ], + "values": [ + 100 + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC21_MatchFirstClaimSet_expected.json b/matcher/testdata/TC21_MatchFirstClaimSet_expected.json new file mode 100644 index 0000000..6f928af --- /dev/null +++ b/matcher/testdata/TC21_MatchFirstClaimSet_expected.json @@ -0,0 +1,81 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "John" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC21_MatchFirstClaimSet_request.json b/matcher/testdata/TC21_MatchFirstClaimSet_request.json new file mode 100644 index 0000000..3ea677b --- /dev/null +++ b/matcher/testdata/TC21_MatchFirstClaimSet_request.json @@ -0,0 +1,44 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claim_sets": [ + [ + "given_name" + ], + [ + "unknown" + ] + ], + "claims": [ + { + "id": "given_name", + "path": [ + "org.iso.18013.5.1", + "given_name" + ] + }, + { + "id": "unknown", + "path": [ + "org.iso.18013.5.1", + "unknown" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC22_MatchSecondClaimSet_expected.json b/matcher/testdata/TC22_MatchSecondClaimSet_expected.json new file mode 100644 index 0000000..6f928af --- /dev/null +++ b/matcher/testdata/TC22_MatchSecondClaimSet_expected.json @@ -0,0 +1,81 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "John" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC22_MatchSecondClaimSet_request.json b/matcher/testdata/TC22_MatchSecondClaimSet_request.json new file mode 100644 index 0000000..b037f98 --- /dev/null +++ b/matcher/testdata/TC22_MatchSecondClaimSet_request.json @@ -0,0 +1,44 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claim_sets": [ + [ + "unknown" + ], + [ + "given_name" + ] + ], + "claims": [ + { + "id": "unknown", + "path": [ + "org.iso.18013.5.1", + "unknown" + ] + }, + { + "id": "given_name", + "path": [ + "org.iso.18013.5.1", + "given_name" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC23_FailAllClaimSets_expected.json b/matcher/testdata/TC23_FailAllClaimSets_expected.json new file mode 100644 index 0000000..5db3910 --- /dev/null +++ b/matcher/testdata/TC23_FailAllClaimSets_expected.json @@ -0,0 +1,18 @@ +{ + "entrySets": {}, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC23_FailAllClaimSets_request.json b/matcher/testdata/TC23_FailAllClaimSets_request.json new file mode 100644 index 0000000..f3e1ee1 --- /dev/null +++ b/matcher/testdata/TC23_FailAllClaimSets_request.json @@ -0,0 +1,44 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "claim_sets": [ + [ + "unknown" + ], + [ + "another_unknown" + ] + ], + "claims": [ + { + "id": "unknown", + "path": [ + "org.iso.18013.5.1", + "unknown" + ] + }, + { + "id": "another_unknown", + "path": [ + "org.iso.18013.5.1", + "another_unknown" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC24_DcqlQuerySingle_expected.json b/matcher/testdata/TC24_DcqlQuerySingle_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC24_DcqlQuerySingle_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC24_DcqlQuerySingle_request.json b/matcher/testdata/TC24_DcqlQuerySingle_request.json new file mode 100644 index 0000000..90ba703 --- /dev/null +++ b/matcher/testdata/TC24_DcqlQuerySingle_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC25_DcqlQuerySetMatch_expected.json b/matcher/testdata/TC25_DcqlQuerySetMatch_expected.json new file mode 100644 index 0000000..d251e90 --- /dev/null +++ b/matcher/testdata/TC25_DcqlQuerySetMatch_expected.json @@ -0,0 +1,39 @@ +{ + "entrySets": { + "req:0;set:0;option:0": { + "entries": { + "0": { + "sdjwt_cred_1": { + "additional_info": "", + "credId": "sdjwt_cred_1", + "disclaimer": "", + "fields": [ + [ + "City", + "Brussels" + ], + [ + "Country", + "Belgium" + ], + [ + "First Name", + "Jane" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "My EU PID", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:0", + "setLength": 1 + } + }, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC25_DcqlQuerySetMatch_request.json b/matcher/testdata/TC25_DcqlQuerySetMatch_request.json new file mode 100644 index 0000000..8015525 --- /dev/null +++ b/matcher/testdata/TC25_DcqlQuerySetMatch_request.json @@ -0,0 +1,31 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credential_sets": [ + { + "options": [ + [ + "pid" + ] + ] + } + ], + "credentials": [ + { + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "urn:eu.europa.ec.eudi:pid:1" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC26_DcqlQuerySetFailRequired_expected.json b/matcher/testdata/TC26_DcqlQuerySetFailRequired_expected.json new file mode 100644 index 0000000..abaa848 --- /dev/null +++ b/matcher/testdata/TC26_DcqlQuerySetFailRequired_expected.json @@ -0,0 +1,4 @@ +{ + "entrySets": {}, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC26_DcqlQuerySetFailRequired_request.json b/matcher/testdata/TC26_DcqlQuerySetFailRequired_request.json new file mode 100644 index 0000000..e7393de --- /dev/null +++ b/matcher/testdata/TC26_DcqlQuerySetFailRequired_request.json @@ -0,0 +1,32 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credential_sets": [ + { + "options": [ + [ + "pid" + ] + ], + "required": true + } + ], + "credentials": [ + { + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "UNKNOWN" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC27_DcqlQuerySetFailOptional_expected.json b/matcher/testdata/TC27_DcqlQuerySetFailOptional_expected.json new file mode 100644 index 0000000..d7cabab --- /dev/null +++ b/matcher/testdata/TC27_DcqlQuerySetFailOptional_expected.json @@ -0,0 +1,125 @@ +{ + "entrySets": { + "req:0;set:0;option:0": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:0", + "setLength": 1 + } + }, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC27_DcqlQuerySetFailOptional_request.json b/matcher/testdata/TC27_DcqlQuerySetFailOptional_request.json new file mode 100644 index 0000000..b7fc047 --- /dev/null +++ b/matcher/testdata/TC27_DcqlQuerySetFailOptional_request.json @@ -0,0 +1,47 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credential_sets": [ + { + "options": [ + [ + "mdl" + ] + ], + "required": true + }, + { + "options": [ + [ + "pid" + ] + ], + "required": false + } + ], + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + }, + { + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "UNKNOWN" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_expected.json b/matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_expected.json new file mode 100644 index 0000000..853483a --- /dev/null +++ b/matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_expected.json @@ -0,0 +1,179 @@ +{ + "entrySets": { + "req:0;set:0;option:0": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "John" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + }, + "1": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:0", + "setLength": 2 + }, + "req:0;set:0;option:1": { + "entries": { + "0": { + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + }, + "1": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:1", + "setLength": 2 + }, + "req:0;set:0;option:2": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "John" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + }, + "1": { + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:2", + "setLength": 2 + } + }, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_request.json b/matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_request.json new file mode 100644 index 0000000..34cd901 --- /dev/null +++ b/matcher/testdata/TC28_DcqlQueryComplexOverlappingSets_request.json @@ -0,0 +1,85 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credential_sets": [ + { + "options": [ + [ + "mdl1", + "mdl3" + ], + [ + "mdl2", + "mdl3" + ], + [ + "mdl1", + "mdl2" + ] + ] + } + ], + "credentials": [ + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "given_name" + ], + "values": [ + "John" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl1", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + }, + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "given_name" + ], + "values": [ + "Jane" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl2", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + }, + { + "claims": [ + { + "path": [ + "org.iso.18013.5.1", + "family_name" + ], + "values": [ + "Doe" + ] + } + ], + "format": "mso_mdoc", + "id": "mdl3", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_expected.json b/matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_expected.json new file mode 100644 index 0000000..ac2799f --- /dev/null +++ b/matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_expected.json @@ -0,0 +1,131 @@ +{ + "entrySets": { + "req:0;set:0;option:0": { + "entries": { + "0": { + "sdjwt_spec_pid": { + "additional_info": "", + "credId": "sdjwt_spec_pid", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ], + [ + "Family Name", + "" + ], + [ + "Street", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Spec PID", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:0", + "setLength": 1 + }, + "req:0;set:0;option:1": { + "entries": { + "0": { + "sdjwt_spec_other_pid": { + "additional_info": "", + "credId": "sdjwt_spec_other_pid", + "disclaimer": "", + "fields": [ + [ + "Given Name", + "" + ], + [ + "Family Name", + "" + ], + [ + "Street", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Other PID", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:1", + "setLength": 1 + }, + "req:0;set:0;option:2": { + "entries": { + "0": { + "sdjwt_spec_reduced_1": { + "additional_info": "", + "credId": "sdjwt_spec_reduced_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Reduced PID", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + }, + "1": { + "sdjwt_spec_reduced_2": { + "additional_info": "", + "credId": "sdjwt_spec_reduced_2", + "disclaimer": "", + "fields": [ + [ + "Zip", + "" + ], + [ + "City", + "" + ], + [ + "Region", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Residence Cred", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;set:0;option:2", + "setLength": 2 + } + }, + "standaloneEntries": [] +} \ No newline at end of file diff --git a/matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_request.json b/matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_request.json new file mode 100644 index 0000000..c803ab6 --- /dev/null +++ b/matcher/testdata/TC29_DcqlQueryOpenID4VPSpecExample_request.json @@ -0,0 +1,154 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credential_sets": [ + { + "options": [ + [ + "pid" + ], + [ + "other_pid" + ], + [ + "pid_reduced_cred_1", + "pid_reduced_cred_2" + ] + ] + }, + { + "options": [ + [ + "nice_to_have" + ] + ], + "required": false + } + ], + "credentials": [ + { + "claims": [ + { + "path": [ + "given_name" + ] + }, + { + "path": [ + "family_name" + ] + }, + { + "path": [ + "address", + "street_address" + ] + } + ], + "format": "dc+sd-jwt", + "id": "pid", + "meta": { + "vct_values": [ + "https://credentials.example.com/identity_credential" + ] + } + }, + { + "claims": [ + { + "path": [ + "given_name" + ] + }, + { + "path": [ + "family_name" + ] + }, + { + "path": [ + "address", + "street_address" + ] + } + ], + "format": "dc+sd-jwt", + "id": "other_pid", + "meta": { + "vct_values": [ + "https://othercredentials.example/pid" + ] + } + }, + { + "claims": [ + { + "path": [ + "family_name" + ] + }, + { + "path": [ + "given_name" + ] + } + ], + "format": "dc+sd-jwt", + "id": "pid_reduced_cred_1", + "meta": { + "vct_values": [ + "https://credentials.example.com/reduced_identity_credential" + ] + } + }, + { + "claims": [ + { + "path": [ + "postal_code" + ] + }, + { + "path": [ + "locality" + ] + }, + { + "path": [ + "region" + ] + } + ], + "format": "dc+sd-jwt", + "id": "pid_reduced_cred_2", + "meta": { + "vct_values": [ + "https://cred.example/residence_credential" + ] + } + }, + { + "claims": [ + { + "path": [ + "rewards_number" + ] + } + ], + "format": "dc+sd-jwt", + "id": "nice_to_have", + "meta": { + "vct_values": [ + "https://company.example/company_rewards" + ] + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC30_ParseV1Unsigned_expected.json b/matcher/testdata/TC30_ParseV1Unsigned_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC30_ParseV1Unsigned_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC30_ParseV1Unsigned_request.json b/matcher/testdata/TC30_ParseV1Unsigned_request.json new file mode 100644 index 0000000..90ba703 --- /dev/null +++ b/matcher/testdata/TC30_ParseV1Unsigned_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC31_ParseV1Signed_expected.json b/matcher/testdata/TC31_ParseV1Signed_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC31_ParseV1Signed_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC31_ParseV1Signed_request.json b/matcher/testdata/TC31_ParseV1Signed_request.json new file mode 100644 index 0000000..cba2df6 --- /dev/null +++ b/matcher/testdata/TC31_ParseV1Signed_request.json @@ -0,0 +1,10 @@ +{ + "requests": [ + { + "data": { + "request": "header.eyJkY3FsX3F1ZXJ5Ijp7ImNyZWRlbnRpYWxzIjpbeyJmb3JtYXQiOiJtc29fbWRvYyIsImlkIjoibWRsIiwibWV0YSI6eyJkb2N0eXBlX3ZhbHVlIjoib3JnLmlzby4xODAxMy41LjEubURMIn19XX19.signature" + }, + "protocol": "openid4vp-v1-signed" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC32_ExtractPaymentSca1_expected.json b/matcher/testdata/TC32_ExtractPaymentSca1_expected.json new file mode 100644 index 0000000..38e0139 --- /dev/null +++ b/matcher/testdata/TC32_ExtractPaymentSca1_expected.json @@ -0,0 +1,79 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC32_ExtractPaymentSca1_request.json b/matcher/testdata/TC32_ExtractPaymentSca1_request.json new file mode 100644 index 0000000..f450e60 --- /dev/null +++ b/matcher/testdata/TC32_ExtractPaymentSca1_request.json @@ -0,0 +1,23 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + }, + "transaction_data": [ + "eyJ0eXBlIjoidXJuOmV1ZGk6c2NhOnBheW1lbnQ6MSIsInBheWxvYWQiOnsicGF5ZWUiOnsibmFtZSI6Ik1lcmNoYW50IFgifSwiYW1vdW50X2Rpc3BsYXkiOiJFVVIgNTAuMDAifSwiY3JlZGVudGlhbF9pZHMiOlsibWRsIl19" + ] + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC33_ExtractPaymentDetails_expected.json b/matcher/testdata/TC33_ExtractPaymentDetails_expected.json new file mode 100644 index 0000000..6b906ce --- /dev/null +++ b/matcher/testdata/TC33_ExtractPaymentDetails_expected.json @@ -0,0 +1,79 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Y", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "USD 10.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Y", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "USD 10.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Y", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "USD 10.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Y", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "USD 10.00", + "type": "Payment", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC33_ExtractPaymentDetails_request.json b/matcher/testdata/TC33_ExtractPaymentDetails_request.json new file mode 100644 index 0000000..72885df --- /dev/null +++ b/matcher/testdata/TC33_ExtractPaymentDetails_request.json @@ -0,0 +1,23 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + }, + "transaction_data": [ + "eyJ0eXBlIjoicGF5bWVudF9kZXRhaWxzIiwicGF5ZWVfbmFtZSI6Ik1lcmNoYW50IFkiLCJwYXltZW50X2Ftb3VudCI6IjEwLjAwIiwicGF5bWVudF9jdXJyZW5jeSI6IlVTRCIsImNyZWRlbnRpYWxfaWRzIjpbIm1kbCJdfQ==" + ] + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC34_ExtractPaymentGeneric_expected.json b/matcher/testdata/TC34_ExtractPaymentGeneric_expected.json new file mode 100644 index 0000000..4050caa --- /dev/null +++ b/matcher/testdata/TC34_ExtractPaymentGeneric_expected.json @@ -0,0 +1,79 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Z", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "Free", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Z", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "Free", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Z", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "Free", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant Z", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "Free", + "type": "Payment", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC34_ExtractPaymentGeneric_request.json b/matcher/testdata/TC34_ExtractPaymentGeneric_request.json new file mode 100644 index 0000000..ba1ed18 --- /dev/null +++ b/matcher/testdata/TC34_ExtractPaymentGeneric_request.json @@ -0,0 +1,23 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + }, + "transaction_data": [ + "eyJtZXJjaGFudF9uYW1lIjoiTWVyY2hhbnQgWiIsImFtb3VudCI6IkZyZWUiLCJjcmVkZW50aWFsX2lkcyI6WyJtZGwiXX0=" + ] + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC35_WasmAddEntryToSet_expected.json b/matcher/testdata/TC35_WasmAddEntryToSet_expected.json new file mode 100644 index 0000000..be6d68b --- /dev/null +++ b/matcher/testdata/TC35_WasmAddEntryToSet_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC35_WasmAddEntryToSet_request.json b/matcher/testdata/TC35_WasmAddEntryToSet_request.json new file mode 100644 index 0000000..90ba703 --- /dev/null +++ b/matcher/testdata/TC35_WasmAddEntryToSet_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC36_WasmPaymentV2_expected.json b/matcher/testdata/TC36_WasmPaymentV2_expected.json new file mode 100644 index 0000000..38e0139 --- /dev/null +++ b/matcher/testdata/TC36_WasmPaymentV2_expected.json @@ -0,0 +1,79 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [], + "merchant_name": "Merchant X", + "metadata_display_text": "", + "subtitle": "", + "title": "", + "transaction_amount": "EUR 50.00", + "type": "Payment", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC36_WasmPaymentV2_request.json b/matcher/testdata/TC36_WasmPaymentV2_request.json new file mode 100644 index 0000000..f450e60 --- /dev/null +++ b/matcher/testdata/TC36_WasmPaymentV2_request.json @@ -0,0 +1,23 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + }, + "transaction_data": [ + "eyJ0eXBlIjoidXJuOmV1ZGk6c2NhOnBheW1lbnQ6MSIsInBheWxvYWQiOnsicGF5ZWUiOnsibmFtZSI6Ik1lcmNoYW50IFgifSwiYW1vdW50X2Rpc3BsYXkiOiJFVVIgNTAuMDAifSwiY3JlZGVudGlhbF9pZHMiOlsibWRsIl19" + ] + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC37_WasmMetadataText_expected.json b/matcher/testdata/TC37_WasmMetadataText_expected.json new file mode 100644 index 0000000..73208fc --- /dev/null +++ b/matcher/testdata/TC37_WasmMetadataText_expected.json @@ -0,0 +1,139 @@ +{ + "entrySets": { + "req:0;null": { + "entries": { + "0": { + "mdoc_cred_1": { + "additional_info": "", + "credId": "mdoc_cred_1", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "Doe" + ], + [ + "Given Name", + "John" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "Verified Member", + "subtitle": "", + "title": "John's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_3": { + "additional_info": "", + "credId": "mdoc_cred_3", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Alice's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_4": { + "additional_info": "", + "credId": "mdoc_cred_4", + "disclaimer": "", + "fields": [ + [ + "Family Name", + "" + ], + [ + "Given Name", + "" + ], + [ + "Age", + "" + ], + [ + "Over 21", + "" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Jane's Driving License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + }, + "mdoc_cred_underage": { + "additional_info": "", + "credId": "mdoc_cred_underage", + "disclaimer": "", + "fields": [ + [ + "Age", + "" + ], + [ + "Over 21", + "Yes" + ] + ], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "", + "title": "Underage License", + "transaction_amount": "", + "type": "Verification", + "warning": "" + } + } + }, + "setId": "req:0;null", + "setLength": 1 + } + }, + "standaloneEntries": [ + { + "additional_info": "", + "credId": "issuance_mdl_1", + "disclaimer": "", + "fields": [], + "merchant_name": "", + "metadata_display_text": "", + "subtitle": "From your local DMV", + "title": "Get a New mDL", + "transaction_amount": "", + "type": "InlineIssuance", + "warning": "" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/TC37_WasmMetadataText_request.json b/matcher/testdata/TC37_WasmMetadataText_request.json new file mode 100644 index 0000000..90ba703 --- /dev/null +++ b/matcher/testdata/TC37_WasmMetadataText_request.json @@ -0,0 +1,20 @@ +{ + "requests": [ + { + "data": { + "dcql_query": { + "credentials": [ + { + "format": "mso_mdoc", + "id": "mdl", + "meta": { + "doctype_value": "org.iso.18013.5.1.mDL" + } + } + ] + } + }, + "protocol": "openid4vp-v1-unsigned" + } + ] +} \ No newline at end of file diff --git a/matcher/testdata/registry.json b/matcher/testdata/registry.json new file mode 100644 index 0000000..c219cc9 --- /dev/null +++ b/matcher/testdata/registry.json @@ -0,0 +1,449 @@ +{ + "credentials": { + "mso_mdoc": { + "org.iso.18013.5.1.mDL": [ + { + "id": "mdoc_cred_1", + "display": { + "verification": { + "title": "John's Driving License", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "org.iso.18013.5.1": { + "family_name": { + "value": "Doe", + "display": { + "verification": { + "display": "Family Name", + "display_value": "Doe" + } + } + }, + "given_name": { + "value": "John", + "display": { + "verification": { + "display": "Given Name", + "display_value": "John" + } + } + }, + "age": { + "value": 21, + "display": { + "verification": { + "display": "Age" + } + } + }, + "age_over_21": { + "value": true, + "display": { + "verification": { + "display": "Over 21", + "display_value": "Yes" + } + } + } + } + } + }, + { + "id": "mdoc_cred_underage", + "display": { + "verification": { + "title": "Underage License", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "org.iso.18013.5.1": { + "age": { + "value": 18, + "display": { + "verification": { + "display": "Age" + } + } + }, + "age_over_21": { + "value": false, + "display": { + "verification": { + "display": "Over 21", + "display_value": "Yes" + } + } + } + } + } + }, + { + "id": "mdoc_cred_3", + "display": { + "verification": { + "title": "Alice's Driving License", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "org.iso.18013.5.1": { + "family_name": { + "value": "Smith", + "display": { + "verification": { + "display": "Family Name" + } + } + }, + "given_name": { + "value": "Alice", + "display": { + "verification": { + "display": "Given Name" + } + } + }, + "age": { + "value": 25, + "display": { + "verification": { + "display": "Age" + } + } + }, + "age_over_21": { + "value": true, + "display": { + "verification": { + "display": "Over 21" + } + } + } + } + } + }, + { + "id": "mdoc_cred_4", + "display": { + "verification": { + "title": "Jane's Driving License", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "org.iso.18013.5.1": { + "family_name": { + "value": "Doe", + "display": { + "verification": { + "display": "Family Name" + } + } + }, + "given_name": { + "value": "Jane", + "display": { + "verification": { + "display": "Given Name" + } + } + }, + "age": { + "value": 30, + "display": { + "verification": { + "display": "Age" + } + } + }, + "age_over_21": { + "value": true, + "display": { + "verification": { + "display": "Over 21" + } + } + } + } + } + } + ] + }, + "dc+sd-jwt": { + "urn:eu.europa.ec.eudi:pid:1": [ + { + "id": "sdjwt_cred_1", + "display": { + "verification": { + "title": "My EU PID", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "user": { + "address": { + "locality": { + "value": "Brussels", + "display": { + "verification": { + "display": "City", + "display_value": "Brussels" + } + } + }, + "country": { + "value": "BE", + "display": { + "verification": { + "display": "Country", + "display_value": "Belgium" + } + } + } + }, + "name": { + "first": { + "value": "Jane", + "display": { + "verification": { + "display": "First Name", + "display_value": "Jane" + } + } + } + } + } + } + } + ], + "https://credentials.example.com/identity_credential": [ + { + "id": "sdjwt_spec_pid", + "display": { + "verification": { + "title": "Spec PID", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "given_name": { + "value": "Alice", + "display": { + "verification": { + "display": "Given Name" + } + } + }, + "family_name": { + "value": "Smith", + "display": { + "verification": { + "display": "Family Name" + } + } + }, + "address": { + "street_address": { + "value": "123 Spec St", + "display": { + "verification": { + "display": "Street" + } + } + } + } + } + } + ], + "https://othercredentials.example/pid": [ + { + "id": "sdjwt_spec_other_pid", + "display": { + "verification": { + "title": "Other PID", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "given_name": { + "value": "Bob", + "display": { + "verification": { + "display": "Given Name" + } + } + }, + "family_name": { + "value": "Jones", + "display": { + "verification": { + "display": "Family Name" + } + } + }, + "address": { + "street_address": { + "value": "456 Other St", + "display": { + "verification": { + "display": "Street" + } + } + } + } + } + } + ], + "https://credentials.example.com/reduced_identity_credential": [ + { + "id": "sdjwt_spec_reduced_1", + "display": { + "verification": { + "title": "Reduced PID", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "given_name": { + "value": "Charlie", + "display": { + "verification": { + "display": "Given Name" + } + } + }, + "family_name": { + "value": "Brown", + "display": { + "verification": { + "display": "Family Name" + } + } + } + } + } + ], + "https://cred.example/residence_credential": [ + { + "id": "sdjwt_spec_reduced_2", + "display": { + "verification": { + "title": "Residence Cred", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "postal_code": { + "value": "12345", + "display": { + "verification": { + "display": "Zip" + } + } + }, + "locality": { + "value": "Townsville", + "display": { + "verification": { + "display": "City" + } + } + }, + "region": { + "value": "State", + "display": { + "verification": { + "display": "Region" + } + } + } + } + } + ], + "https://company.example/company_rewards": [ + { + "id": "sdjwt_spec_rewards", + "display": { + "verification": { + "title": "Rewards", + "icon": { + "start": 4, + "length": 10 + } + } + }, + "paths": { + "rewards_number": { + "value": "9999", + "display": { + "verification": { + "display": "Rewards No" + } + } + } + } + } + ] + }, + "issuance": { + "mso_mdoc": [ + { + "id": "issuance_mdl_1", + "title": "Get a New mDL", + "subtitle": "From your local DMV", + "icon": { + "start": 4, + "length": 10 + }, + "supported": [ + "org.iso.18013.5.1.mDL" + ] + } + ], + "dc+sd-jwt": [ + { + "id": "issuance_pid_1", + "title": "Get a New EU PID", + "subtitle": "Official Digital ID", + "icon": { + "start": 4, + "length": 10 + }, + "supported": [ + "urn:eu.europa.ec.eudi:pid:1" + ] + } + ] + } + } +} \ No newline at end of file