Repository navigation
create-pki: add the verifier's dNSName to the signing cert (same key and root) - #80
Merged
Merged
Conversation
… re-issuing the signing cert from the same key and root The vc-verifier's client_id is x509_san_dns:<host> and it signs request objects with the shared signing certificate, whose SAN lacked that host. Deploy passes the verifier's public host; signing_cert_current() checks it exactly (no substring or wildcard match). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…erifier.signingCertDnsSan), set only for gdc Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Inherited environment variables can bypass the opt-in, and host-only reissuance can remove the existing issuer URI.
2 open issues
What changed in this PR
Adds an opt-in verifier DNS SAN to the shared signing certificate, retaining the existing key and root for strict OpenID4VP client identity checks.
Changes:
- Adds DNS SAN generation and certificate freshness checks.
- Enables the option for gdc only, defaulting it off elsewhere.
- Adds tests for key preservation, SAN matching, idempotency, and deployment gating.
| File | Description |
|---|---|
| values-base.yaml | Documents and defaults the option off. |
| tests/test_create_pki_verifier_san.py | Tests certificate reissuance and opt-in behavior. |
| sirosid_core/deploy.py | Passes the verifier hostname when enabled. |
| fixtures/create-pki.sh | Adds and checks the verifier DNS SAN. |
| environments/gdc.yaml | Enables the option for gdc. |
Review effort: Balanced
| fi | ||
| if [ -n "${SIGNING_CERT_VERIFIER_HOST:-}" ]; then | ||
| # ", " or line start before and ", " or line end after, so `verifier.example` does not match `x.verifier.example`. | ||
| grep -qE "(^|[ ,])DNS:${SIGNING_CERT_VERIFIER_HOST//./\\.}(,|$)" <<<"$sans" || return 1 |
Comment on lines
+138
to
+139
| if ((ctx.spec.values or {}).get("verifier") or {}).get("signingCertDnsSan"): | ||
| env_vars["SIGNING_CERT_VERIFIER_HOST"] = naming.host("vc-verifier") |
Contributor
Author
|
Contained in and superseded by #81 (the branch gdc runs, with the pin provenance). Review and merge that one and close this, or merge this first and I rebase it. |
leifj
added a commit
that referenced
this pull request
Oct 21, 2026
…ase.yaml's signingCertDnsSan from #80) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.

Not deployed, not merged. The re-issued certificate reaches gdc with the verifier rollout, when the coordination session says go (a Fly deploy overwrites the public cert files on every run).
Why
The vc-verifier's OpenID4VP client_id is
x509_san_dns:<host of public_url>(gdc:sirosid-gdc-vc-verifier.fly.dev) and it signs request objects with the shared signing certificate (verifier.key_config->/pki/signing_ec_*.pem, the same key and certificate as the issuer's DS certificate). That certificate's SAN waslocalhost, vc-issuer, vc-verifier+ the issuer URI, with nosirosid-gdc-vc-verifier.fly.dev. Nothing in gdc rejects it today (the wallet-backend engine leaves the client_id-vs-SAN check to the PDP), but a strict wallet or relying party checking the client_id against the request's x5c leaf would.What changes
fixtures/create-pki.sh:SIGNING_CERT_VERIFIER_HOSTaddsDNS.4;signing_cert_current()re-issues the leaf when the SAN is missing, exactly as it already does forSIGNING_CERT_ISSUER_URL. The re-issue is from the EXISTING key and root. The match is exact (x.verifier.exampledoes not satisfyverifier.example;.is escaped).sirosid_core/deploy.py: passesnaming.host("vc-verifier")ONLY when the environment setsvalues.verifier.signingCertDnsSan: true(default false invalues-base.yaml; set only inenvironments/gdc.yaml). Every other environment's certificate is left exactly as it is on deploy; a test asserts that, and that gdc is the only environment file that opts in.Impact on existing credentials: none
Each already-issued mdoc embeds its own DS leaf, which chains to the unchanged root, and the key is unchanged. The PDP's mDOC IACA trust depends on the IACA and the issuer URI SAN, both preserved. Proven in
tests/test_create_pki_verifier_san.py: the private key, public key and root are byte-identical after the re-issue, the new leaf verifies against the unchanged root, the issuer URI andvc-issuerSANs survive, a second run is a no-op, and unset leaves an existing cert alone.Live PDP replay (2026-10-20, scratch copy of gdc's PKI re-issued with this script, nothing deployed)
x509_san_dns:sirosid-gdc-vc-verifier.fly.dev, actioncredential-verifierandverifierverifiers)mdoc-issuermdoc-issuercredential-issuerpid-issuers)credential-verifierCaveat
This is a test-environment shortcut: the verifier and the issuer share one key. A deployment that signs credentials for real should use separate issuer and verifier keys and certificates (a verifier cert from the same CA carrying only the verifier host, its own secret and
verifier.key_configpaths).Tests
New: 9 in
tests/test_create_pki_verifier_san.py, proven non-vacuous (the script change reverted fails two; making the pass-through unconditional fails the 'every other environment is unchanged' test). deploy, control-plane, naming and fly-payload suites pass.DEPLOYED on gdc (2026-10-20/21) via
deploy/gdc-nymauth-verifier(contains this PR and #79, neither merged)The signing leaf was re-issued with the DNS SAN
sirosid-gdc-vc-verifier.fly.dev; the key and rootCA are byte-identical to before. Live PDP replay of the deployed chain: verifierx509_san_dns:sirosid-gdc-vc-verifier.fly.dev(credential-verifier) true, issuermdoc-issuertrue (mDOC IACA),credential-issuertrue (whitelist). The verifier's request object x5c leaf carries the dNSName, and the verifier no longer logs "certificate does not cover PublicURL host".🤖 Generated with Claude Code