Contract badge-vc-verify/v1
Contract identifier: https://probityai.github.io/agent-evidence-vectors/contract/badge-vc-verify/v1
Corpus: corpora/vectors-badge-vc-verify. Carried in release v0.37.0.
Badge credential vectors
Cases for badge-vc-verify/v1: does your verifier accept an agent badge issued as a W3C Verifiable Credential in a compact JWS (EdDSA) only when the issuer is trusted, the signing key belongs to that issuer, the signature covers the exact bytes sent, the credential is inside its validity window, and the issuer's own status store does not list it as revoked? Each case is one case.json: the token, the verification time, the key material resolved for each issuer DID, the trusted issuers, and the issuer's revocation store.
Each denied case departs from a conformant case in one place and is allowed by a verifier that skips the check it names. The revocation case, for example, is allowed by a verifier that reads only the token, because the issuer's status store is the authority and the token carries no sign of revocation.
The checks, in the order a verifier applies them
The verifier names the first check that fails.
| Check | Reason on failure |
|---|---|
case.json carries contractId |
contract_id_missing |
contractId is the badge contract |
contract_id_unknown |
| the case has the fields and types the contract names | malformed_case |
the token is three unpadded base64url parts; the header is a JSON object with alg EdDSA and a kid of the form <did>#<fragment> |
jws_malformed |
the payload is a credential with id, issuer, issuanceDate, credentialSubject.id and VerifiableCredential among its type, and every time is RFC 3339 |
credential_malformed |
the credential's issuer is in trustedIssuers |
issuer_not_trusted |
the kid's DID is the credential's issuer and its fragment names a key of that issuer |
issuer_key_binding |
the Ed25519 signature verifies over the ASCII bytes header.payload |
signature_invalid |
issuanceDate is not after verificationTime |
not_yet_valid |
expirationDate, when present, is after verificationTime |
expired |
the credential's id is not in status.revoked |
revoked |
A case that passes every check is allow with reason verified. Resolving a DID to its keys is outside this corpus: the case carries the keys the verifier resolved.
Running
pip install agent-evidence-vectors
agent-evidence-vectors --corpus vectors-badge-vc-verify
To judge your own verifier, run it as <verifier> <case-dir>/case.json --json. It prints one JSON object carrying decision and reason, and exits 0 for allow and 1 for deny. Pass it to the corpus with --verifier.
Controls
Every denied case departs from a conformant case in one place, and each check is forced by at least one case: switching it off changes a verdict. A verifier that denies everything fails the allowed cases, and one that allows everything fails the denied ones. A fixture whose bytes differ from the manifest is refused before execution. tests/test_corpus.py holds each of these as a test, and regenerates the corpus byte for byte from gen_vectors.py.