Skip to content

Trust digital-credentials.dev as a verifier on gdc - #38

Merged
leifj merged 3 commits into
mainfrom
env/gdc-trust-dcdev
Sep 7, 2026
Merged

leifj merged 3 commits into
mainfrom
env/gdc-trust-dcdev

Conversation

@leifj

@leifj leifj commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Google's public DC API test site. Browser-initiated presentation against it reached the wallet on a Pixel and was then declined by trust evaluation — all three registries said no, the whitelist because the subject simply wasn't in it:

Verifier 'https://digital-credentials.dev' is not trusted:
  sirosid-gdc Fly whitelist  — subject not in whitelist for action 'credential-verifier'
  sirosid-gdc mDOC IACA      — issuer not in allowlist
  sirosid-gdc RICAL          — empty X5C chain

Why the plain origin

That's what a whitelist match actually compares against. An unsigned DC API request carries no signing certificate, so the subject is the origin Chrome verified; a signed request using the x509_san_dns scheme is normalized to https://<host> before the match runs. Only x509_hash: subjects are compared un-normalized — so if the site's signed requests turn out to use that scheme, its hash needs adding verbatim alongside this, and the PDP's denial message quotes the exact string to paste.

No reader-CA root added either. The site's request-signing certificate is self-signed rather than chained (see values-fly.yaml's 0.12.1 → 0.13.0 note, which names digital-credentials.dev specifically), so it's trusted by hash-pinning — the one scheme go-trust deliberately skips chain validation for. A root wouldn't help.

Verified through build_fly_values_overlay that the entry lands in the verifiers list, which credential-verifier maps to, and confirmed in the rendered pdp.yaml before deploying.

Deployed

make fly-up ENV=gdc — the PDP is live with the entry. Two things worth recording from that run:

The PKI guard did its job. The first attempt refused to continue: my worktree had no local vc-pki cache while sirosid-gdc-vc-registry already had a signing-key secret, and generating a fresh keypair would have deployed a mismatched chain against the old private key — breaking verification of the mDL this environment has already issued, which is the exact credential we're testing with. I restored the original PKI byte-identically from the checkout that first deployed gdc rather than rotating.

The VC-service registration step fails with HTTP 401, and it isn't from this change. No local working copy holds the adminToken that's actually deployed — I tried all three, all 401 — so that step would fail identically for anyone running fly-up ENV=gdc today. It does not affect the PDP whitelist, and it does not remove existing registrations (the wallet's issuers/verifiers live in mongo from the original deploy and the wallet still works). Worth its own fix: either the deployed token needs recovering into a checkout, or fly-up should read it back rather than assume the local copy is authoritative.

I also confirmed nothing was rotated: --file-secret /main-secrets/jwtSecret=jwtSecret references the existing Fly secret by name, and there were zero secrets set jwtSecret|adminToken invocations in the run.

leifj and others added 2 commits September 7, 2026 15:23
Signup returned 400 from /auth/passkey/register/finish with "Error validating
origin": wallet-backend's rp_origins did not contain the apk-key-hash the app
presents, so the registration ceremony could not complete. Login with an
already-registered passkey kept working, which makes this look like a server
regression rather than a missing accept-list entry - it is not one.

The keys previously lived only in `.android-apps`, which is gitignored and
per-checkout. So `make fly-up ENV=gdc` from a working copy that happens not to
have that file deploys an rp_origins with the app's keys missing, silently.
That is exactly what happened on 2026-09-07, from a fresh worktree.

Environment state the environment needs belongs in the environment file, where
anyone's next deploy reproduces it - the same argument the file's own header
makes. `.android-apps` is still read and still adds to this; nothing here
replaces it.

Three keys, all org.siros.sdk.sample: the repo's committed debug keystore
(sample-app/debug.keystore, what CI and a clean checkout build with), a local
per-developer debug keystore, and an older one kept so devices still carrying
that build can log in.

Verified through load_android_apps() that both the committed and the local key
reach the identity list fly-up registers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013szWPnZ8FzEDWZkYN1MNKs
Google's public DC API test site. Browser-initiated presentation against it
reached the wallet and was then declined by trust evaluation - all three
registries said no, the whitelist because the subject simply was not in it:

    subject not in whitelist for action 'credential-verifier'

Written as the plain origin, which is what a match actually compares against.
An unsigned DC API request carries no signing certificate, so the subject is
the origin Chrome verified; a signed request using the x509_san_dns scheme is
normalized to https://<host> before the match runs. Only x509_hash: subjects
are compared un-normalized, so if the site's signed requests use that scheme
its hash has to be added verbatim alongside this - the PDP's denial message
quotes the exact string.

No reader-CA root added. The site's request-signing certificate is self-signed
rather than chained (see values-fly.yaml's 0.12.1 -> 0.13.0 note), so it is
trusted by hash-pinning, which is the one scheme go-trust deliberately skips
chain validation for - a root would not help.

Verified through build_fly_values_overlay that the entry lands in the
`verifiers` list, which `credential-verifier` maps to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013szWPnZ8FzEDWZkYN1MNKs
@leifj
leifj force-pushed the env/gdc-trust-dcdev branch from 7926e6f to f836bcc Compare September 7, 2026 13:24
The origin entry alone was not enough. Its signed requests identify with the
x509_hash client_id scheme, and the PDP quoted the subject in its denial:

    whitelist denied request
      subject=x509_hash:f1drGLOIT4kDBlJVsD-_33igSf5uwRnq3yO2NvcXEW0
      reason="subject not in whitelist for action 'credential-verifier'"

Pasted verbatim, because x509_hash: subjects are compared un-normalized while
x509_san_dns:/x509_san_uri: are reduced to https://<host> before the match.
That asymmetry is why both entries are needed and neither covers the other: the
origin matches an unsigned request, where there is no certificate and the
subject is the origin Chrome verified; the hash matches a signed one.

Hash-pinning is itself the trust decision for this scheme, so go-trust skips
chain validation and no reader-CA root is needed - which is just as well, since
the site's signing certificate is self-signed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013szWPnZ8FzEDWZkYN1MNKs
@leifj
leifj requested a lite review from Copilot September 7, 2026 13:25
@leifj
leifj merged commit 5898717 into main Sep 7, 2026
1 check passed
@leifj
leifj deleted the env/gdc-trust-dcdev branch September 7, 2026 13:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The YAML changes match the environment config schema and are consistent with existing trust/Android-app identity handling in the deploy scripts.

Pull request overview

Updates the persisted gdc Fly environment configuration to trust Google’s public Digital Credentials API test site for browser-initiated OpenID4VP/DC API presentations, and to make the environment’s Android sample-app RP origin allowlist reproducible across redeploys.

Changes:

  • Adds https://digital-credentials.dev and its observed x509_hash:... subject to trusted_verifiers for the credential-verifier whitelist action.
  • Persists multiple org.siros.sdk.sample signing key fingerprints under android_apps so fly-up ENV=gdc consistently renders rp_origins to include the app’s actual APK key hashes.
File summaries
File Description
environments/gdc.yaml Extends trusted_verifiers for digital-credentials.dev (origin + x509 hash) and persists Android app signing keys via android_apps for reproducible WebAuthn RP origins on redeploy.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants