feat(openid4vci): parse untrusted Credential Offers and Issuer Metadata - #177
Merged
Conversation
Add parse_credential_offer (OID4VCI 1.0 §4.1.1) and parse_credential_issuer_metadata (§11.2.3) to openvc.openid4vci — the fail-closed discovery parsers of ADR-0007 D7, returning the frozen CredentialOffer / CredentialIssuerMetadata dataclasses. The issuer identifier and every endpoint URL must be absolute https, hardened by adversarial review: control characters, userinfo, query/fragment and lazily-raising ports/brackets are all rejected with typed errors, so the stored identifier compares byte-for-byte against a key proof's aud and no raw ValueError escapes the taxonomy. Pinned against the spec's own §4.1.1/§4.1.2/§11.2.3 examples and the recorded EU-reference-issuer artifacts from #147. Closes #142
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
parse_credential_offer(OID4VCI 1.0 §4.1.1) andparse_credential_issuer_metadata(§11.2.3) inopenvc.openid4vci— the consume-and-verify half of OID4VCI discovery, per ADR-0007 D7 (parsers in, builders out).CredentialOffer/CredentialIssuerMetadata(registered intest_return_contract.py), typed errorsCredentialOfferMalformed/IssuerMetadataMalformed, wire constantsGRANT_AUTHORIZATION_CODE/GRANT_PRE_AUTHORIZED_CODE.credential_issuerand every endpoint URL must be absolute https;credential_configuration_idsnon-empty/distinct/non-empty strings;batch_sizean int ≥ 2; unknowngrantsmembers and all extension points preserved (typed fields +raw), never dropped. Nothing is fetched.Adversarial review (attacker-controlled JSON)
Spawned per the runbook. One merge-blocking finding + three follow-ups, all fixed in this branch with regression tests:
urlparseValueErrorescaped the typed taxonomy on hostile URLs (https://[::1). Now wrapped, andhostname/portare forced so lazyValueErrors raise here, not in the caller's fetch code.urlparsesilently strips\t\r\n; the stored identifier would disagree with the host an HTTP client connects to (and with the signedaud). Control chars/whitespace now rejected.https://legit@evil), plus query/fragment on an identifier that compares byte-for-byte againstaud. All rejected.https://./ bad ports accepted. Subsumed by the forced-accessor fix.Golden vectors
Happy paths run against material we did not write: the spec's own §4.1.1/§4.1.2/§11.2.3 examples (new
spec/fixtures with_provenance) and the recorded EU-reference-issuer offer/metadata artifacts already vendored by #147. The hostile corpus covers deep nesting, wrong types, empties, duplicates, and every URL bypass above.Gate
flake8+mypy+ 1758 tests green;test_docs_blocksexecutes the new wiki snippet. CHANGELOG entry under1.25.0 — unreleased.Closes #142